diff --git a/app/layout/centrallayout.cpp b/app/layout/centrallayout.cpp index b90341f4..caa2211e 100644 --- a/app/layout/centrallayout.cpp +++ b/app/layout/centrallayout.cpp @@ -1,510 +1,491 @@ /* * Copyright 2017 Smith AR * Michail Vourlakos * * This file is part of Latte-Dock * * Latte-Dock is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * Latte-Dock 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 . */ #include "centrallayout.h" // local #include "sharedlayout.h" #include "../lattecorona.h" #include "../screenpool.h" #include "../layouts/importer.h" #include "../layouts/manager.h" #include "../layouts/synchronizer.h" #include "../settings/universalsettings.h" #include "../view/view.h" #include "../../liblatte2/types.h" -// Qt -#include - // KDE #include #include namespace Latte { CentralLayout::CentralLayout(QObject *parent, QString layoutFile, QString assignedName) : Layout::GenericLayout(parent, layoutFile, assignedName) { if (m_loadedCorrectly) { loadConfig(); init(); } } CentralLayout::~CentralLayout() { if (!m_layoutFile.isEmpty()) { m_layoutGroup.sync(); } } void CentralLayout::unloadContainments() { Layout::GenericLayout::unloadContainments(); if (m_sharedLayout) { disconnectSharedConnections(); m_sharedLayout->removeCentralLayout(this); } } void CentralLayout::init() { connect(this, &CentralLayout::activitiesChanged, this, &CentralLayout::saveConfig); connect(this, &CentralLayout::disableBordersForMaximizedWindowsChanged, this, &CentralLayout::saveConfig); connect(this, &CentralLayout::sharedLayoutNameChanged, this, &CentralLayout::saveConfig); connect(this, &CentralLayout::showInMenuChanged, this, &CentralLayout::saveConfig); } void CentralLayout::initToCorona(Latte::Corona *corona) { if (GenericLayout::initToCorona(corona)) { connect(m_corona->universalSettings(), &UniversalSettings::canDisableBordersChanged, this, [&]() { if (m_corona->universalSettings()->canDisableBorders()) { kwin_setDisabledMaximizedBorders(disableBordersForMaximizedWindows()); } else { kwin_setDisabledMaximizedBorders(false); } }); if (m_corona->layoutsManager()->memoryUsage() == Types::SingleLayout && m_corona->universalSettings()->canDisableBorders()) { kwin_setDisabledMaximizedBorders(disableBordersForMaximizedWindows()); } else if (m_corona->layoutsManager()->memoryUsage() == Types::MultipleLayouts) { connect(m_corona->layoutsManager(), &Layouts::Manager::currentLayoutNameChanged, this, [&]() { if (m_corona->universalSettings()->canDisableBorders() && m_corona->layoutsManager()->currentLayoutName() == name()) { kwin_setDisabledMaximizedBorders(disableBordersForMaximizedWindows()); } }); } //! Request the SharedLayout in case there is one and Latte is functioning in MultipleLayouts mode if (m_corona->layoutsManager()->memoryUsage() == Types::MultipleLayouts && !m_sharedLayoutName.isEmpty()) { if (m_corona->layoutsManager()->synchronizer()->registerAtSharedLayout(this, m_sharedLayoutName)) { setSharedLayout(m_corona->layoutsManager()->synchronizer()->sharedLayout(m_sharedLayoutName)); } } } } bool CentralLayout::disableBordersForMaximizedWindows() const { return m_disableBordersForMaximizedWindows; } void CentralLayout::setDisableBordersForMaximizedWindows(bool disable) { if (m_disableBordersForMaximizedWindows == disable) { return; } m_disableBordersForMaximizedWindows = disable; kwin_setDisabledMaximizedBorders(disable); emit disableBordersForMaximizedWindowsChanged(); } bool CentralLayout::kwin_disabledMaximizedBorders() const { - //! Identify Plasma Desktop version - QProcess process; - process.start("kreadconfig5 --file kwinrc --group Windows --key BorderlessMaximizedWindows"); - process.waitForFinished(); - QString output(process.readAllStandardOutput()); - - output = output.remove("\n"); + if (!m_corona) { + return false; + } - return (output == "true"); + return m_corona->universalSettings()->kwin_borderlessMaximizedWindowsEnabled(); } void CentralLayout::kwin_setDisabledMaximizedBorders(bool disable) { - if (kwin_disabledMaximizedBorders() == disable) { + if (!m_corona) { return; } - QString disableText = disable ? "true" : "false"; - - QProcess process; - QString commandStr = "kwriteconfig5 --file kwinrc --group Windows --key BorderlessMaximizedWindows --type bool " + disableText; - process.start(commandStr); - process.waitForFinished(); - - QDBusInterface iface("org.kde.KWin", "/KWin", "", QDBusConnection::sessionBus()); - - if (iface.isValid()) { - iface.call("reconfigure"); - } - + m_corona->universalSettings()->kwin_setDisabledMaximizedBorders(disable); } bool CentralLayout::showInMenu() const { return m_showInMenu; } void CentralLayout::setShowInMenu(bool show) { if (m_showInMenu == show) { return; } m_showInMenu = show; emit showInMenuChanged(); } Layout::Type CentralLayout::type() const { return Layout::Type::Central; } QStringList CentralLayout::activities() const { return m_activities; } void CentralLayout::setActivities(QStringList activities) { if (m_activities == activities) { return; } m_activities = activities; emit activitiesChanged(); } QString CentralLayout::sharedLayoutName() const { return m_sharedLayoutName; } void CentralLayout::setSharedLayoutName(QString name) { if (m_sharedLayoutName == name || (!Layouts::Importer::layoutExists(name) && !name.isEmpty())) { return; } m_sharedLayoutName = name; emit sharedLayoutNameChanged(); } SharedLayout *CentralLayout::sharedLayout() const { return m_sharedLayout; } void CentralLayout::setSharedLayout(SharedLayout *layout) { if (m_sharedLayout == layout) { return; } disconnectSharedConnections(); m_sharedLayout = layout; if (layout) { setSharedLayoutName(m_sharedLayout->name()); //! attach new signals m_sharedConnections << connect(m_sharedLayout, &Layout::GenericLayout::viewsCountChanged, this, &Layout::GenericLayout::viewsCountChanged); m_sharedConnections << connect(m_sharedLayout, &Layout::AbstractLayout::nameChanged, this, [this]() { setSharedLayoutName(m_sharedLayout->name()); }); m_sharedConnections << connect(m_sharedLayout, &Layout::GenericLayout::viewEdgeChanged, this, [this]() { syncLatteViewsToScreens(); }); } else { setSharedLayoutName(QString()); } syncLatteViewsToScreens(); emit viewsCountChanged(); } void CentralLayout::disconnectSharedConnections() { //! drop old signals for (const auto &sc : m_sharedConnections) { QObject::disconnect(sc); } m_sharedConnections.clear(); } void CentralLayout::loadConfig() { m_disableBordersForMaximizedWindows = m_layoutGroup.readEntry("disableBordersForMaximizedWindows", false); m_showInMenu = m_layoutGroup.readEntry("showInMenu", false); m_activities = m_layoutGroup.readEntry("activities", QStringList()); QString sharedLayoutName = m_layoutGroup.readEntry("sharedLayout", QString()); if (Layouts::Importer::layoutExists(sharedLayoutName)) { m_sharedLayoutName = sharedLayoutName; } emit activitiesChanged(); } void CentralLayout::saveConfig() { qDebug() << "CENTRAL layout is saving... for layout:" << m_layoutName; m_layoutGroup.writeEntry("showInMenu", m_showInMenu); m_layoutGroup.writeEntry("disableBordersForMaximizedWindows", m_disableBordersForMaximizedWindows); m_layoutGroup.writeEntry("sharedLayout", m_sharedLayoutName); m_layoutGroup.writeEntry("activities", m_activities); m_layoutGroup.sync(); } //! OVERRIDES void CentralLayout::addView(Plasma::Containment *containment, bool forceOnPrimary, int explicitScreen, Layout::ViewsMap *occupied) { if (m_sharedLayout) { //! consider already occupied edges from SharedLayout Layout::ViewsMap ocMap = m_sharedLayout->validViewsMap(); qDebug() << " HIGH PRIORITY ALREADY OCCUPIED EDGES :: " << ocMap; Layout::GenericLayout::addView(containment, forceOnPrimary, explicitScreen, &ocMap); } else { Layout::GenericLayout::addView(containment, forceOnPrimary, explicitScreen, occupied); } } bool CentralLayout::configViewIsShown() const { bool genericShown = GenericLayout::configViewIsShown(); if (m_sharedLayout) { return (m_sharedLayout->configViewIsShown() || genericShown); } return genericShown; } const QStringList CentralLayout::appliedActivities() { if (!m_corona) { return {}; } if (m_corona->layoutsManager()->memoryUsage() == Types::SingleLayout) { return {"0"}; } else if (m_corona->layoutsManager()->memoryUsage() == Types::MultipleLayouts) { if (m_activities.isEmpty()) { return m_corona->layoutsManager()->synchronizer()->orphanedActivities(); } else { return m_activities; } } else { return {"0"}; } } QList CentralLayout::latteViews() { if (m_sharedLayout) { QList views = Layout::GenericLayout::latteViews(); views << m_sharedLayout->latteViews(); return views; } return Layout::GenericLayout::latteViews(); } int CentralLayout::viewsCount(int screen) const { if (!m_corona) { return 0; } int views = Layout::GenericLayout::viewsCount(screen); if (m_sharedLayout) { QScreen *scr = m_corona->screenPool()->screenForId(screen); for (const auto view : m_sharedLayout->latteViews()) { if (view && view->screen() == scr && !view->containment()->destroyed()) { ++views; } } } return views; } int CentralLayout::viewsCount(QScreen *screen) const { if (!m_corona) { return 0; } int views = Layout::GenericLayout::viewsCount(screen); if (m_sharedLayout) { for (const auto view : m_sharedLayout->latteViews()) { if (view && view->screen() == screen && !view->containment()->destroyed()) { ++views; } } } return views; } int CentralLayout::viewsCount() const { if (!m_corona) { return 0; } int views = Layout::GenericLayout::viewsCount(); if (m_sharedLayout) { for (const auto view : m_sharedLayout->latteViews()) { if (view && view->containment() && !view->containment()->destroyed()) { ++views; } } } return views; } QList CentralLayout::availableEdgesForView(QScreen *scr, Latte::View *forView) const { using Plasma::Types; QList edges{Types::BottomEdge, Types::LeftEdge, Types::TopEdge, Types::RightEdge}; if (!m_corona) { return edges; } edges = Layout::GenericLayout::availableEdgesForView(scr, forView); if (m_sharedLayout) { for (const auto view : m_sharedLayout->latteViews()) { //! make sure that availabe edges takes into account only views that should be excluded, //! this is why the forView should not be excluded if (view && view != forView && view->positioner()->currentScreenName() == scr->name()) { edges.removeOne(view->location()); } } } return edges; } QList CentralLayout::freeEdges(QScreen *scr) const { using Plasma::Types; QList edges{Types::BottomEdge, Types::LeftEdge, Types::TopEdge, Types::RightEdge}; if (!m_corona) { return edges; } edges = Layout::GenericLayout::freeEdges(scr); if (m_sharedLayout) { for (const auto view : m_sharedLayout->latteViews()) { if (view && view->positioner()->currentScreenName() == scr->name()) { edges.removeOne(view->location()); } } } return edges; } QList CentralLayout::freeEdges(int screen) const { using Plasma::Types; QList edges{Types::BottomEdge, Types::LeftEdge, Types::TopEdge, Types::RightEdge}; if (!m_corona) { return edges; } edges = Layout::GenericLayout::freeEdges(screen); QScreen *scr = m_corona->screenPool()->screenForId(screen); if (m_sharedLayout) { for (const auto view : m_sharedLayout->latteViews()) { if (view && scr && view->positioner()->currentScreenName() == scr->name()) { edges.removeOne(view->location()); } } } return edges; } Types::ViewType CentralLayout::latteViewType(int containmentId) const { for (const auto view : m_latteViews) { if (view->containment() && view->containment()->id() == containmentId) { return view->type(); } } if (m_sharedLayout) { return m_sharedLayout->latteViewType(containmentId); } return Types::DockView; } QList CentralLayout::sortedLatteViews(QList views) { QList vws = latteViews(); return Layout::GenericLayout::sortedLatteViews(vws); } QList CentralLayout::viewsWithPlasmaShortcuts() { QList combined = Layout::GenericLayout::viewsWithPlasmaShortcuts(); if (m_sharedLayout) { combined << m_sharedLayout->viewsWithPlasmaShortcuts(); } return combined; } void CentralLayout::syncLatteViewsToScreens(Layout::ViewsMap *occupiedMap) { if (m_sharedLayout) { Layout::ViewsMap map = m_sharedLayout->validViewsMap(); Layout::GenericLayout::syncLatteViewsToScreens(&map); } else { Layout::GenericLayout::syncLatteViewsToScreens(); } } } diff --git a/app/settings/settingsdialog.cpp b/app/settings/settingsdialog.cpp index 7cf39981..c43c9167 100644 --- a/app/settings/settingsdialog.cpp +++ b/app/settings/settingsdialog.cpp @@ -1,2055 +1,2055 @@ /* * Copyright 2017 Smith AR * Michail Vourlakos * * This file is part of Latte-Dock * * Latte-Dock is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * Latte-Dock 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 . * */ #include "settingsdialog.h" // local #include "universalsettings.h" #include "ui_settingsdialog.h" #include "../lattecorona.h" #include "../screenpool.h" #include "../layout/genericlayout.h" #include "../layout/centrallayout.h" #include "../layout/sharedlayout.h" #include "../layouts/importer.h" #include "../layouts/manager.h" #include "../layouts/synchronizer.h" #include "../liblatte2/types.h" #include "../plasma/extended/theme.h" #include "delegates/activitiesdelegate.h" #include "delegates/checkboxdelegate.h" #include "delegates/colorcmbboxdelegate.h" #include "delegates/layoutnamedelegate.h" #include "delegates/shareddelegate.h" // Qt #include #include #include #include #include #include #include #include #include #include #include #include // KDE #include #include #include #include #include #include #include #include namespace Latte { const int IDCOLUMN = 0; const int HIDDENTEXTCOLUMN = 1; const int COLORCOLUMN = 2; const int NAMECOLUMN = 3; const int MENUCOLUMN = 4; const int BORDERSCOLUMN = 5; const int ACTIVITYCOLUMN = 6; const int SHAREDCOLUMN = 7; const int SCREENTRACKERDEFAULTVALUE = 2500; const int OUTLINEDEFAULTWIDTH = 1; const QChar CheckMark{0x2714}; SettingsDialog::SettingsDialog(QWidget *parent, Latte::Corona *corona) : QDialog(parent), ui(new Ui::SettingsDialog), m_corona(corona) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose, true); setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint); resize(m_corona->universalSettings()->layoutsWindowSize()); connect(ui->buttonBox->button(QDialogButtonBox::Apply), &QPushButton::clicked , this, &SettingsDialog::apply); connect(ui->buttonBox->button(QDialogButtonBox::RestoreDefaults), &QPushButton::clicked , this, &SettingsDialog::restoreDefaults); m_model = new QStandardItemModel(m_corona->layoutsManager()->layouts().count(), 6, this); ui->layoutsView->setModel(m_model); ui->layoutsView->horizontalHeader()->setStretchLastSection(true); ui->layoutsView->verticalHeader()->setVisible(false); connect(m_corona->layoutsManager(), &Layouts::Manager::currentLayoutNameChanged, this, &SettingsDialog::layoutsChanged); connect(m_corona->layoutsManager(), &Layouts::Manager::centralLayoutsChanged, this, &SettingsDialog::layoutsChanged); QString iconsPath(m_corona->kPackage().path() + "../../plasmoids/org.kde.latte.containment/contents/icons/"); //!find the available colors QDir layoutDir(iconsPath); QStringList filter; filter.append(QString("*print.jpg")); QStringList files = layoutDir.entryList(filter, QDir::Files | QDir::NoSymLinks); QStringList colors; for (auto &file : files) { int colorEnd = file.lastIndexOf("print.jpg"); QString color = file.remove(colorEnd, 9); colors.append(color); } ui->layoutsView->setItemDelegateForColumn(NAMECOLUMN, new LayoutNameDelegate(this)); ui->layoutsView->setItemDelegateForColumn(COLORCOLUMN, new ColorCmbBoxDelegate(this, iconsPath, colors)); ui->layoutsView->setItemDelegateForColumn(MENUCOLUMN, new CheckBoxDelegate(this)); ui->layoutsView->setItemDelegateForColumn(BORDERSCOLUMN, new CheckBoxDelegate(this)); ui->layoutsView->setItemDelegateForColumn(ACTIVITYCOLUMN, new ActivitiesDelegate(this)); ui->layoutsView->setItemDelegateForColumn(SHAREDCOLUMN, new SharedDelegate(this)); m_inMemoryButtons = new QButtonGroup(this); m_inMemoryButtons->addButton(ui->singleToolBtn, Latte::Types::SingleLayout); m_inMemoryButtons->addButton(ui->multipleToolBtn, Latte::Types::MultipleLayouts); m_inMemoryButtons->setExclusive(true); if (KWindowSystem::isPlatformWayland()) { m_inMemoryButtons->button(Latte::Types::MultipleLayouts)->setEnabled(false); } m_mouseSensitivityButtons = new QButtonGroup(this); m_mouseSensitivityButtons->addButton(ui->lowSensitivityBtn, Latte::Types::LowSensitivity); m_mouseSensitivityButtons->addButton(ui->mediumSensitivityBtn, Latte::Types::MediumSensitivity); m_mouseSensitivityButtons->addButton(ui->highSensitivityBtn, Latte::Types::HighSensitivity); m_mouseSensitivityButtons->setExclusive(true); ui->screenTrackerSpinBox->setValue(m_corona->universalSettings()->screenTrackerInterval()); ui->outlineSpinBox->setValue(m_corona->themeExtended()->outlineWidth()); //! About Menu QMenuBar *menuBar = new QMenuBar(this); // QMenuBar *rightAlignedMenuBar = new QMenuBar(menuBar); layout()->setMenuBar(menuBar); //menuBar->setCornerWidget(rightAlignedMenuBar); QMenu *fileMenu = new QMenu(i18n("File"), menuBar); menuBar->addMenu(fileMenu); QMenu *layoutMenu = new QMenu(i18n("Layout"), menuBar); //rightAlignedMenuBar->addMenu(helpMenu); menuBar->addMenu(layoutMenu); QMenu *helpMenu = new QMenu(i18n("Help"), menuBar); //rightAlignedMenuBar->addMenu(helpMenu); menuBar->addMenu(helpMenu); QAction *screensAction = fileMenu->addAction(i18n("Sc&reens...")); screensAction->setIcon(QIcon::fromTheme("document-properties")); screensAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_R)); QAction *quitAction = fileMenu->addAction(i18n("&Quit Latte")); quitAction->setIcon(QIcon::fromTheme("application-exit")); quitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q)); m_editLayoutAction = layoutMenu->addAction(i18nc("edit layout","&Edit...")); m_editLayoutAction->setIcon(QIcon::fromTheme("document-edit")); m_editLayoutAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_E)); m_editLayoutAction->setToolTip("You can edit layout file when layout is not active or locked"); QAction *infoLayoutAction = layoutMenu->addAction(i18nc("layout information","&Information...")); infoLayoutAction->setIcon(QIcon::fromTheme("document-properties")); infoLayoutAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_I)); QAction *aboutAction = helpMenu->addAction(i18n("About Latte")); aboutAction->setIcon(QIcon::fromTheme("latte-dock")); //! RTL support for labels in preferences if (qApp->layoutDirection() == Qt::RightToLeft) { ui->behaviorLbl->setAlignment(Qt::AlignRight | Qt::AlignTop); ui->mouseSensetivityLbl->setAlignment(Qt::AlignRight | Qt::AlignTop); ui->delayLbl->setAlignment(Qt::AlignRight | Qt::AlignTop); } loadSettings(); //! SIGNALS connect(m_model, &QStandardItemModel::itemChanged, this, &SettingsDialog::itemChanged); connect(ui->layoutsView->selectionModel(), &QItemSelectionModel::currentRowChanged, this, [&]() { updatePerLayoutButtonsState(); updateApplyButtonsState(); }); connect(m_inMemoryButtons, static_cast(&QButtonGroup::buttonToggled), [ = ](int id, bool checked) { updateApplyButtonsState(); updateSharedLayoutsStates(); updateSharedLayoutsUiElements(); }); connect(m_mouseSensitivityButtons, static_cast(&QButtonGroup::buttonToggled), [ = ](int id, bool checked) { updateApplyButtonsState(); }); connect(ui->screenTrackerSpinBox, QOverload::of(&QSpinBox::valueChanged), [ = ](int i) { updateApplyButtonsState(); }); connect(ui->outlineSpinBox, QOverload::of(&QSpinBox::valueChanged), [ = ](int i) { updateApplyButtonsState(); }); connect(ui->autostartChkBox, &QCheckBox::stateChanged, this, &SettingsDialog::updateApplyButtonsState); connect(ui->badges3DStyleChkBox, &QCheckBox::stateChanged, this, &SettingsDialog::updateApplyButtonsState); connect(ui->metaPressChkBox, &QCheckBox::stateChanged, this, &SettingsDialog::updateApplyButtonsState); connect(ui->metaPressHoldChkBox, &QCheckBox::stateChanged, this, &SettingsDialog::updateApplyButtonsState); connect(ui->infoWindowChkBox, &QCheckBox::stateChanged, this, &SettingsDialog::updateApplyButtonsState); connect(ui->tabWidget, &QTabWidget::currentChanged, this, &SettingsDialog::updateApplyButtonsState); connect(ui->noBordersForMaximizedChkBox, &QCheckBox::stateChanged, this, [&]() { bool noBordersForMaximized = ui->noBordersForMaximizedChkBox->isChecked(); if (noBordersForMaximized) { ui->layoutsView->setColumnHidden(BORDERSCOLUMN, false); } else { ui->layoutsView->setColumnHidden(BORDERSCOLUMN, true); } updateApplyButtonsState(); }); connect(aboutAction, &QAction::triggered, m_corona, &Latte::Corona::aboutApplication); connect(quitAction, &QAction::triggered, this, [&]() { close(); m_corona->closeApplication(); }); connect(m_editLayoutAction, &QAction::triggered, this, [&]() { QString file = idForRow(ui->layoutsView->currentIndex().row()); if (!file.isEmpty()) { QProcess::startDetached("kwrite \"" + file + "\""); } }); connect(infoLayoutAction, &QAction::triggered, this, &SettingsDialog::showLayoutInformation); connect(screensAction, &QAction::triggered, this, &SettingsDialog::showScreensInformation); //! update all layouts view when runningActivities changed. This way we update immediately //! the running Activities in Activities checkboxes which are shown as bold connect(m_corona->activitiesConsumer(), &KActivities::Consumer::runningActivitiesChanged, this, [&]() { ui->layoutsView->update(); }); blockDeleteOnActivityStopped(); } SettingsDialog::~SettingsDialog() { qDebug() << Q_FUNC_INFO; qDeleteAll(m_layouts); if (m_model) { delete m_model; } if (m_corona && m_corona->universalSettings()) { m_corona->universalSettings()->setLayoutsWindowSize(size()); QStringList columnWidths; columnWidths << QString::number(ui->layoutsView->columnWidth(COLORCOLUMN)); columnWidths << QString::number(ui->layoutsView->columnWidth(NAMECOLUMN)); columnWidths << QString::number(ui->layoutsView->columnWidth(MENUCOLUMN)); columnWidths << QString::number(ui->layoutsView->columnWidth(BORDERSCOLUMN)); Latte::Types::LayoutsMemoryUsage inMemoryOption = static_cast(m_inMemoryButtons->checkedId()); if (inMemoryOption == Latte::Types::MultipleLayouts) { columnWidths << QString::number(ui->layoutsView->columnWidth(ACTIVITYCOLUMN)); } else { //! In Single Mode, keed recorded value for ACTIVITYCOLUMN QStringList currentWidths = m_corona->universalSettings()->layoutsColumnWidths(); if (currentWidths.count()>=5) { columnWidths << currentWidths[4]; } } m_corona->universalSettings()->setLayoutsColumnWidths(columnWidths); } m_inMemoryButtons->deleteLater(); m_mouseSensitivityButtons->deleteLater(); for (const auto &tempDir : m_tempDirectories) { QDir tDir(tempDir); if (tDir.exists() && tempDir.startsWith("/tmp/")) { tDir.removeRecursively(); } } } void SettingsDialog::blockDeleteOnActivityStopped() { connect(m_corona->activitiesConsumer(), &KActivities::Consumer::runningActivitiesChanged, this, [&]() { m_blockDeleteOnReject = true; m_activityClosedTimer.start(); }); m_activityClosedTimer.setSingleShot(true); m_activityClosedTimer.setInterval(500); connect(&m_activityClosedTimer, &QTimer::timeout, this, [&]() { m_blockDeleteOnReject = false; }); } QStringList SettingsDialog::activities() { return m_corona->layoutsManager()->synchronizer()->activities(); } QStringList SettingsDialog::availableActivities() { return m_availableActivities; } QStringList SettingsDialog::availableSharesFor(int row) { QStringList availables; QStringList regs; for (int i = 0; i < m_model->rowCount(); ++i) { QString id = m_model->data(m_model->index(i, IDCOLUMN), Qt::DisplayRole).toString(); QStringList shares = m_model->data(m_model->index(i, SHAREDCOLUMN), Qt::UserRole).toStringList(); if (i != row) { if (shares.isEmpty()) { availables << id; } else { regs << shares; } } } for (const auto r : regs) { availables.removeAll(r); } return availables; } void SettingsDialog::toggleCurrentPage() { if (ui->tabWidget->currentIndex() == 0) { ui->tabWidget->setCurrentIndex(1); } else { ui->tabWidget->setCurrentIndex(0); } } void SettingsDialog::on_newButton_clicked() { qDebug() << Q_FUNC_INFO; //! find Default preset path for (const auto &preset : m_corona->layoutsManager()->presetsPaths()) { QString presetName = CentralLayout::layoutName(preset); if (presetName == "Default") { QByteArray presetNameChars = presetName.toUtf8(); const char *prset_str = presetNameChars.data(); presetName = uniqueLayoutName(i18n(prset_str)); addLayoutForFile(preset, presetName, true, false); break; } } } void SettingsDialog::on_copyButton_clicked() { qDebug() << Q_FUNC_INFO; int row = ui->layoutsView->currentIndex().row(); if (row < 0) { return; } //! Update original layout before copying if this layout is active if (m_corona->layoutsManager()->memoryUsage() == Types::MultipleLayouts) { QString lName = (m_model->data(m_model->index(row, NAMECOLUMN), Qt::DisplayRole)).toString(); Layout::GenericLayout *generic = m_corona->layoutsManager()->synchronizer()->layout(lName); if (generic) { generic->syncToLayoutFile(); } } QString tempDir = uniqueTempDirectory(); QString id = m_model->data(m_model->index(row, IDCOLUMN), Qt::DisplayRole).toString(); QString color = m_model->data(m_model->index(row, COLORCOLUMN), Qt::BackgroundRole).toString(); QString textColor = m_model->data(m_model->index(row, COLORCOLUMN), Qt::UserRole).toString(); QString layoutName = uniqueLayoutName(m_model->data(m_model->index(row, NAMECOLUMN), Qt::DisplayRole).toString()); bool menu = m_model->data(m_model->index(row, MENUCOLUMN), Qt::DisplayRole).toString() == CheckMark; bool disabledBorders = m_model->data(m_model->index(row, BORDERSCOLUMN), Qt::DisplayRole).toString() == CheckMark; QString copiedId = tempDir + "/" + layoutName + ".layout.latte"; QFile(id).copy(copiedId); QFileInfo newFileInfo(copiedId); if (newFileInfo.exists() && !newFileInfo.isWritable()) { QFile(copiedId).setPermissions(QFileDevice::ReadUser | QFileDevice::WriteUser | QFileDevice::ReadGroup | QFileDevice::ReadOther); } CentralLayout *settings = new CentralLayout(this, copiedId); m_layouts[copiedId] = settings; insertLayoutInfoAtRow(row + 1, copiedId, color, textColor, layoutName, menu, disabledBorders, QStringList(), false); ui->layoutsView->selectRow(row + 1); } void SettingsDialog::on_downloadButton_clicked() { qDebug() << Q_FUNC_INFO; KNS3::DownloadDialog dialog(QStringLiteral("latte-layouts.knsrc"), this); dialog.resize(m_corona->universalSettings()->downloadWindowSize()); dialog.exec(); bool layoutAdded{false}; if (!dialog.changedEntries().isEmpty() || !dialog.installedEntries().isEmpty()) { for (const auto &entry : dialog.installedEntries()) { for (const auto &entryFile : entry.installedFiles()) { Layouts::Importer::LatteFileVersion version = Layouts::Importer::fileVersion(entryFile); if (version == Layouts::Importer::LayoutVersion2) { layoutAdded = true; addLayoutForFile(entryFile); break; } } } } m_corona->universalSettings()->setDownloadWindowSize(dialog.size()); if (layoutAdded) { apply(); } } void SettingsDialog::on_removeButton_clicked() { qDebug() << Q_FUNC_INFO; int row = ui->layoutsView->currentIndex().row(); if (row < 0) { return; } QString layoutName = m_model->data(m_model->index(row, NAMECOLUMN), Qt::DisplayRole).toString(); if (m_corona->layoutsManager()->synchronizer()->centralLayout(layoutName)) { return; } m_model->removeRow(row); updateApplyButtonsState(); row = qMax(row - 1, 0); ui->layoutsView->selectRow(row); } void SettingsDialog::on_lockedButton_clicked() { qDebug() << Q_FUNC_INFO; int row = ui->layoutsView->currentIndex().row(); if (row < 0) { return; } bool lockedModel = m_model->data(m_model->index(row, NAMECOLUMN), Qt::UserRole).toBool(); m_model->setData(m_model->index(row, NAMECOLUMN), QVariant(!lockedModel), Qt::UserRole); updatePerLayoutButtonsState(); updateApplyButtonsState(); } void SettingsDialog::on_sharedButton_clicked() { qDebug() << Q_FUNC_INFO; int row = ui->layoutsView->currentIndex().row(); if (row < 0) { return; } if (isShared(row)) { m_model->setData(m_model->index(row, SHAREDCOLUMN), QStringList(), Qt::UserRole); } else { bool assigned{false}; QStringList assignedList; QStringList availableShares = availableSharesFor(row); for (const auto &id : availableShares) { QString name = nameForId(id); if (m_corona->layoutsManager()->synchronizer()->layout(name)) { assignedList << id; m_model->setData(m_model->index(row, SHAREDCOLUMN), assignedList, Qt::UserRole); assigned = true; break; } } if (!assigned && availableShares.count()>0) { assignedList << availableShares[0]; m_model->setData(m_model->index(row, SHAREDCOLUMN), assignedList, Qt::UserRole); assigned = true; } } updatePerLayoutButtonsState(); updateApplyButtonsState(); } void SettingsDialog::on_importButton_clicked() { qDebug() << Q_FUNC_INFO; QFileDialog *fileDialog = new QFileDialog(this, i18nc("import layout/configuration", "Import Layout/Configuration") , QDir::homePath() , QStringLiteral("layout.latte")); fileDialog->setFileMode(QFileDialog::AnyFile); fileDialog->setAcceptMode(QFileDialog::AcceptOpen); fileDialog->setDefaultSuffix("layout.latte"); QStringList filters; filters << QString(i18nc("import latte layout", "Latte Dock Layout file v0.2") + "(*.layout.latte)") << QString(i18nc("import latte layouts/configuration", "Latte Dock Full Configuration file (v0.1, v0.2)") + "(*.latterc)"); fileDialog->setNameFilters(filters); connect(fileDialog, &QFileDialog::finished , fileDialog, &QFileDialog::deleteLater); connect(fileDialog, &QFileDialog::fileSelected , this, [&](const QString & file) { Layouts::Importer::LatteFileVersion version = Layouts::Importer::fileVersion(file); qDebug() << "VERSION :::: " << version; if (version == Layouts::Importer::LayoutVersion2) { addLayoutForFile(file); } else if (version == Layouts::Importer::ConfigVersion1) { auto msg = new QMessageBox(this); msg->setIcon(QMessageBox::Warning); msg->setWindowTitle(i18n("Import: Configuration file version v0.1")); msg->setText( i18n("You are going to import an old version v0.1 configuration file.
Be careful, importing the entire configuration will erase all your current configuration!!!

Alternative, you can import safely from this file
only the contained layouts...
")); msg->setStandardButtons(QMessageBox::Cancel); QPushButton *fullBtn = new QPushButton(msg); QPushButton *layoutsBtn = new QPushButton(msg); fullBtn->setText(i18nc("import full configuration", "Full Configuration")); fullBtn->setIcon(QIcon::fromTheme("settings")); layoutsBtn->setText(i18nc("import only the layouts", "Only Layouts")); layoutsBtn->setIcon(QIcon::fromTheme("user-identity")); msg->addButton(fullBtn, QMessageBox::AcceptRole); msg->addButton(layoutsBtn, QMessageBox::AcceptRole); msg->setDefaultButton(layoutsBtn); connect(msg, &QMessageBox::finished, msg, &QMessageBox::deleteLater); msg->open(); connect(layoutsBtn, &QPushButton::clicked , this, [ &, file](bool check) { importLayoutsFromV1ConfigFile(file); }); connect(fullBtn, &QPushButton::clicked , this, [ &, file](bool check) { //!NOTE: Restart latte for import the new configuration QProcess::startDetached(qGuiApp->applicationFilePath() + " --import-full \"" + file + "\""); qGuiApp->exit(); }); } else if (version == Layouts::Importer::ConfigVersion2) { auto msg = new QMessageBox(this); msg->setIcon(QMessageBox::Warning); msg->setWindowTitle(i18n("Import: Configuration file version v0.2")); msg->setText( i18n("You are going to import a v0.2 configuration file.
Be careful, importing will erase all your current configuration!!!

Would you like to proceed?")); msg->setStandardButtons(QMessageBox::Yes | QMessageBox::No); msg->setDefaultButton(QMessageBox::No); connect(msg, &QMessageBox::finished, this, [ &, msg, file](int result) { if (result == QMessageBox::Yes) { //!NOTE: Restart latte for import the new configuration msg->deleteLater(); QProcess::startDetached(qGuiApp->applicationFilePath() + " --import-full \"" + file + "\""); qGuiApp->exit(); } }); msg->open(); } }); fileDialog->open(); } bool SettingsDialog::importLayoutsFromV1ConfigFile(QString file) { KTar archive(file, QStringLiteral("application/x-tar")); archive.open(QIODevice::ReadOnly); //! if the file isnt a tar archive if (archive.isOpen()) { QDir tempDir{uniqueTempDirectory()}; const auto archiveRootDir = archive.directory(); for (const auto &name : archiveRootDir->entries()) { auto fileEntry = archiveRootDir->file(name); fileEntry->copyTo(tempDir.absolutePath()); } QString name = Layouts::Importer::nameOfConfigFile(file); QString applets(tempDir.absolutePath() + "/" + "lattedock-appletsrc"); if (QFile(applets).exists()) { if (m_corona->layoutsManager()->importer()->importOldLayout(applets, name, false, tempDir.absolutePath())) { addLayoutForFile(tempDir.absolutePath() + "/" + name + ".layout.latte", name, false); } QString alternativeName = name + "-" + i18nc("layout", "Alternative"); if (m_corona->layoutsManager()->importer()->importOldLayout(applets, alternativeName, false, tempDir.absolutePath())) { addLayoutForFile(tempDir.absolutePath() + "/" + alternativeName + ".layout.latte", alternativeName, false); } } return true; } return false; } void SettingsDialog::on_exportButton_clicked() { int row = ui->layoutsView->currentIndex().row(); if (row < 0) { return; } QString layoutExported = m_model->data(m_model->index(row, IDCOLUMN), Qt::DisplayRole).toString(); //! Update ALL active original layouts before exporting, //! this is needed because the export method can export also the full configuration qDebug() << Q_FUNC_INFO; m_corona->layoutsManager()->synchronizer()->syncActiveLayoutsToOriginalFiles(); QFileDialog *fileDialog = new QFileDialog(this, i18nc("export layout/configuration", "Export Layout/Configuration") , QDir::homePath(), QStringLiteral("layout.latte")); fileDialog->setFileMode(QFileDialog::AnyFile); fileDialog->setAcceptMode(QFileDialog::AcceptSave); fileDialog->setDefaultSuffix("layout.latte"); QStringList filters; QString filter1(i18nc("export layout", "Latte Dock Layout file v0.2") + "(*.layout.latte)"); QString filter2(i18nc("export full configuration", "Latte Dock Full Configuration file v0.2") + "(*.latterc)"); filters << filter1 << filter2; fileDialog->setNameFilters(filters); connect(fileDialog, &QFileDialog::finished , fileDialog, &QFileDialog::deleteLater); connect(fileDialog, &QFileDialog::fileSelected , this, [ &, layoutExported](const QString & file) { auto showNotificationError = []() { auto notification = new KNotification("export-fail", KNotification::CloseOnTimeout); notification->setText(i18nc("export layout", "Failed to export layout")); notification->sendEvent(); }; if (QFile::exists(file) && !QFile::remove(file)) { showNotificationError(); return; } if (file.endsWith(".layout.latte")) { if (!QFile(layoutExported).copy(file)) { showNotificationError(); return; } QFileInfo newFileInfo(file); if (newFileInfo.exists() && !newFileInfo.isWritable()) { QFile(file).setPermissions(QFileDevice::ReadUser | QFileDevice::WriteUser | QFileDevice::ReadGroup | QFileDevice::ReadOther); } CentralLayout layoutS(this, file); layoutS.setActivities(QStringList()); layoutS.clearLastUsedActivity(); //NOTE: The pointer is automatically deleted when the event is closed auto notification = new KNotification("export-done", KNotification::CloseOnTimeout); notification->setActions({i18nc("export layout", "Open location")}); notification->setText(i18nc("export layout", "Layout exported successfully")); connect(notification, &KNotification::action1Activated , this, [file]() { QDesktopServices::openUrl({QFileInfo(file).canonicalPath()}); }); notification->sendEvent(); } else if (file.endsWith(".latterc")) { auto showNotificationError = []() { auto notification = new KNotification("export-fail", KNotification::CloseOnTimeout); notification->setText(i18nc("import/export config", "Failed to export configuration")); notification->sendEvent(); }; if (m_corona->layoutsManager()->importer()->exportFullConfiguration(file)) { auto notification = new KNotification("export-done", KNotification::CloseOnTimeout); notification->setActions({i18nc("import/export config", "Open location")}); notification->setText(i18nc("import/export config", "Full Configuration exported successfully")); connect(notification, &KNotification::action1Activated , this, [file]() { QDesktopServices::openUrl({QFileInfo(file).canonicalPath()}); }); notification->sendEvent(); } else { showNotificationError(); } } }); fileDialog->open(); } void SettingsDialog::requestImagesDialog(int row) { QStringList mimeTypeFilters; mimeTypeFilters << "image/jpeg" // will show "JPEG image (*.jpeg *.jpg) << "image/png"; // will show "PNG image (*.png)" QFileDialog dialog(this); dialog.setMimeTypeFilters(mimeTypeFilters); QString background = m_model->data(m_model->index(row, COLORCOLUMN), Qt::BackgroundRole).toString(); if (background.startsWith("/") && QFileInfo(background).exists()) { dialog.setDirectory(QFileInfo(background).absolutePath()); dialog.selectFile(background); } if (dialog.exec()) { QStringList files = dialog.selectedFiles(); if (files.count() > 0) { m_model->setData(m_model->index(row, COLORCOLUMN), files[0], Qt::BackgroundRole); } } } void SettingsDialog::requestColorsDialog(int row) { QColorDialog dialog(this); QString textColor = m_model->data(m_model->index(row, COLORCOLUMN), Qt::UserRole).toString(); dialog.setCurrentColor(QColor(textColor)); if (dialog.exec()) { qDebug() << dialog.selectedColor().name(); m_model->setData(m_model->index(row, COLORCOLUMN), dialog.selectedColor().name(), Qt::UserRole); } } void SettingsDialog::accept() { qDebug() << Q_FUNC_INFO; if (saveAllChanges()) { deleteLater(); } } void SettingsDialog::reject() { qDebug() << Q_FUNC_INFO; if (!m_blockDeleteOnReject) { deleteLater(); } } void SettingsDialog::apply() { qDebug() << Q_FUNC_INFO; saveAllChanges(); o_settings = currentSettings(); o_settingsLayouts = currentLayoutsSettings(); updateApplyButtonsState(); updatePerLayoutButtonsState(); } void SettingsDialog::restoreDefaults() { qDebug() << Q_FUNC_INFO; if (ui->tabWidget->currentIndex() == 0) { //! Default layouts missing from layouts list for (const auto &preset : m_corona->layoutsManager()->presetsPaths()) { QString presetName = CentralLayout::layoutName(preset); QByteArray presetNameChars = presetName.toUtf8(); const char *prset_str = presetNameChars.data(); presetName = i18n(prset_str); if (!nameExistsInModel(presetName)) { addLayoutForFile(preset, presetName); } } } else if (ui->tabWidget->currentIndex() == 1) { //! Defaults for general Latte settings ui->autostartChkBox->setChecked(true); ui->badges3DStyleChkBox->setChecked(true); ui->infoWindowChkBox->setChecked(true); ui->metaPressChkBox->setChecked(false); ui->metaPressHoldChkBox->setChecked(true); ui->noBordersForMaximizedChkBox->setChecked(false); ui->highSensitivityBtn->setChecked(true); ui->screenTrackerSpinBox->setValue(SCREENTRACKERDEFAULTVALUE); ui->outlineSpinBox->setValue(OUTLINEDEFAULTWIDTH); } } void SettingsDialog::addLayoutForFile(QString file, QString layoutName, bool newTempDirectory, bool showNotification) { if (layoutName.isEmpty()) { layoutName = CentralLayout::layoutName(file); } QString copiedId; if (newTempDirectory) { QString tempDir = uniqueTempDirectory(); copiedId = tempDir + "/" + layoutName + ".layout.latte"; QFile(file).copy(copiedId); } else { copiedId = file; } QFileInfo newFileInfo(copiedId); if (newFileInfo.exists() && !newFileInfo.isWritable()) { QFile(copiedId).setPermissions(QFileDevice::ReadUser | QFileDevice::WriteUser | QFileDevice::ReadGroup | QFileDevice::ReadOther); } if (m_layouts.contains(copiedId)) { CentralLayout *oldSettings = m_layouts.take(copiedId); delete oldSettings; } CentralLayout *settings = new CentralLayout(this, copiedId); m_layouts[copiedId] = settings; QString id = copiedId; QString color = settings->color(); QString textColor = settings->textColor(); QString background = settings->background(); bool menu = settings->showInMenu(); bool disabledBorders = settings->disableBordersForMaximizedWindows(); bool locked = !settings->isWritable(); layoutName = uniqueLayoutName(layoutName); int row = ascendingRowFor(layoutName); if (background.isEmpty()) { insertLayoutInfoAtRow(row, copiedId, color, QString(), layoutName, menu, disabledBorders, QStringList(), locked); } else { insertLayoutInfoAtRow(row, copiedId, background, textColor, layoutName, menu, disabledBorders, QStringList(), locked); } ui->layoutsView->selectRow(row); if (showNotification) { //NOTE: The pointer is automatically deleted when the event is closed auto notification = new KNotification("import-done", KNotification::CloseOnTimeout); notification->setText(i18nc("import-done", "Layout: %0 imported successfully
").arg(layoutName)); notification->sendEvent(); } } void SettingsDialog::loadSettings() { m_initLayoutPaths.clear(); m_model->clear(); m_sharesMap.clear(); int i = 0; QStringList brokenLayouts; if (m_corona->layoutsManager()->memoryUsage() == Types::MultipleLayouts) { m_corona->layoutsManager()->synchronizer()->syncActiveLayoutsToOriginalFiles(); } for (const auto layout : m_corona->layoutsManager()->layouts()) { QString layoutPath = QDir::homePath() + "/.config/latte/" + layout + ".layout.latte"; m_initLayoutPaths.append(layoutPath); CentralLayout *central = new CentralLayout(this, layoutPath); m_layouts[layoutPath] = central; QString background = central->background(); //! add central layout properties if (background.isEmpty()) { insertLayoutInfoAtRow(i, layoutPath, central->color(), QString(), central->name(), central->showInMenu(), central->disableBordersForMaximizedWindows(), central->activities(), !central->isWritable()); } else { insertLayoutInfoAtRow(i, layoutPath, background, central->textColor(), central->name(), central->showInMenu(), central->disableBordersForMaximizedWindows(), central->activities(), !central->isWritable()); } //! create initial SHARES maps QString shared = central->sharedLayoutName(); if (!shared.isEmpty()) { m_sharesMap[shared].append(layoutPath); } qDebug() << "counter:" << i << " total:" << m_model->rowCount(); i++; if (central->name() == m_corona->layoutsManager()->currentLayoutName()) { ui->layoutsView->selectRow(i - 1); } Layout::GenericLayout *generic = m_corona->layoutsManager()->synchronizer()->layout(central->name()); if ((generic && generic->layoutIsBroken()) || (!generic && central->layoutIsBroken())) { brokenLayouts.append(central->name()); } } //! update SHARES map keys in order to use the #settingsid(s) QStringList forremoval; //! remove these records after updating for (QHash::iterator i=m_sharesMap.begin(); i!=m_sharesMap.end(); ++i) { forremoval << i.key(); } //! update keys for (QHash::iterator i=m_sharesMap.begin(); i!=m_sharesMap.end(); ++i) { QString shareid = idForRow(rowForName(i.key())); m_sharesMap[shareid] = i.value(); } //! remove deprecated keys for (const auto &key : forremoval) { m_sharesMap.remove(key); } qDebug() << "SHARES MAP ::: " << m_sharesMap; for (QHash::iterator i=m_sharesMap.begin(); i!=m_sharesMap.end(); ++i) { int sharedPos = rowForId(i.key()); if (sharedPos >= 0) { m_model->setData(m_model->index(sharedPos, SHAREDCOLUMN), i.value(), Qt::UserRole); } } recalculateAvailableActivities(); m_model->setHorizontalHeaderItem(IDCOLUMN, new QStandardItem(QString("#path"))); m_model->setHorizontalHeaderItem(COLORCOLUMN, new QStandardItem(QIcon::fromTheme("games-config-background"), QString(i18nc("column for layout background", "Background")))); m_model->setHorizontalHeaderItem(NAMECOLUMN, new QStandardItem(QString(i18nc("column for layout name", "Name")))); m_model->setHorizontalHeaderItem(MENUCOLUMN, new QStandardItem(QString(i18nc("column for layout to show in menu", "In Menu")))); m_model->setHorizontalHeaderItem(BORDERSCOLUMN, new QStandardItem(QString(i18nc("column for layout to hide borders for maximized windows", "Borderless")))); m_model->setHorizontalHeaderItem(ACTIVITYCOLUMN, new QStandardItem(QIcon::fromTheme("activities"), QString(i18nc("column for layout to show which activities is assigned to", "Activities")))); m_model->setHorizontalHeaderItem(SHAREDCOLUMN, new QStandardItem(QIcon::fromTheme("document-share"), QString(i18nc("column for shared layout to show which layouts is assigned to", "Shared To")))); //! this line should be commented for debugging layouts window functionality ui->layoutsView->setColumnHidden(IDCOLUMN, true); ui->layoutsView->setColumnHidden(HIDDENTEXTCOLUMN, true); if (m_corona->universalSettings()->canDisableBorders()) { ui->layoutsView->setColumnHidden(BORDERSCOLUMN, false); } else { ui->layoutsView->setColumnHidden(BORDERSCOLUMN, true); } ui->layoutsView->resizeColumnsToContents(); QStringList columnWidths = m_corona->universalSettings()->layoutsColumnWidths(); if (!columnWidths.isEmpty()) { for (int i=0; ilayoutsView->setColumnWidth(COLORCOLUMN+i, columnWidths[i].toInt()); } } if (m_corona->layoutsManager()->memoryUsage() == Types::SingleLayout) { ui->singleToolBtn->setChecked(true); } else if (m_corona->layoutsManager()->memoryUsage() == Types::MultipleLayouts) { ui->multipleToolBtn->setChecked(true); } updatePerLayoutButtonsState(); updateSharedLayoutsStates(); ui->autostartChkBox->setChecked(m_corona->universalSettings()->autostart()); ui->badges3DStyleChkBox->setChecked(m_corona->universalSettings()->badges3DStyle()); ui->infoWindowChkBox->setChecked(m_corona->universalSettings()->showInfoWindow()); - ui->metaPressChkBox->setChecked(m_corona->universalSettings()->metaForwardedToLatte()); + ui->metaPressChkBox->setChecked(m_corona->universalSettings()->kwin_metaForwardedToLatte()); ui->metaPressHoldChkBox->setChecked(m_corona->universalSettings()->metaPressAndHoldEnabled()); ui->noBordersForMaximizedChkBox->setChecked(m_corona->universalSettings()->canDisableBorders()); if (m_corona->universalSettings()->mouseSensitivity() == Types::LowSensitivity) { ui->lowSensitivityBtn->setChecked(true); } else if (m_corona->universalSettings()->mouseSensitivity() == Types::MediumSensitivity) { ui->mediumSensitivityBtn->setChecked(true); } else if (m_corona->universalSettings()->mouseSensitivity() == Types::HighSensitivity) { ui->highSensitivityBtn->setChecked(true); } o_settings = currentSettings(); o_settingsLayouts = currentLayoutsSettings(); updateApplyButtonsState(); updateSharedLayoutsUiElements(); //! there are broken layouts and the user must be informed! if (brokenLayouts.count() > 0) { auto msg = new QMessageBox(this); msg->setIcon(QMessageBox::Warning); msg->setWindowTitle(i18n("Layout Warning")); msg->setText(i18n("The layout(s) %0 have broken configuration!!! Please remove them to improve the system stability...").arg(brokenLayouts.join(","))); msg->setStandardButtons(QMessageBox::Ok); msg->open(); } } QList SettingsDialog::currentSettings() { QList settings; settings << m_inMemoryButtons->checkedId(); settings << (int)ui->autostartChkBox->isChecked(); settings << (int)ui->badges3DStyleChkBox->isChecked(); settings << (int)ui->infoWindowChkBox->isChecked(); settings << (int)ui->metaPressChkBox->isChecked(); settings << (int)ui->metaPressHoldChkBox->isChecked(); settings << (int)ui->noBordersForMaximizedChkBox->isChecked(); settings << m_mouseSensitivityButtons->checkedId(); settings << ui->screenTrackerSpinBox->value(); settings << ui->outlineSpinBox->value(); settings << m_model->rowCount(); return settings; } QStringList SettingsDialog::currentLayoutsSettings() { QStringList layoutSettings; for (int i = 0; i < m_model->rowCount(); ++i) { QString id = m_model->data(m_model->index(i, IDCOLUMN), Qt::DisplayRole).toString(); QString color = m_model->data(m_model->index(i, COLORCOLUMN), Qt::BackgroundRole).toString(); QString textColor = m_model->data(m_model->index(i, COLORCOLUMN), Qt::UserRole).toString(); QString name = m_model->data(m_model->index(i, NAMECOLUMN), Qt::DisplayRole).toString(); bool locked = m_model->data(m_model->index(i, NAMECOLUMN), Qt::UserRole).toBool(); bool menu = m_model->data(m_model->index(i, MENUCOLUMN), Qt::DisplayRole).toString() == CheckMark; bool borders = m_model->data(m_model->index(i, BORDERSCOLUMN), Qt::DisplayRole).toString() == CheckMark; QStringList lActivities = m_model->data(m_model->index(i, ACTIVITYCOLUMN), Qt::UserRole).toStringList(); QStringList shares = m_model->data(m_model->index(i, SHAREDCOLUMN), Qt::UserRole).toStringList(); layoutSettings << id; layoutSettings << color; layoutSettings << textColor; layoutSettings << name; layoutSettings << QString::number((int)locked); layoutSettings << QString::number((int)menu); layoutSettings << QString::number((int)borders); layoutSettings << lActivities; layoutSettings << shares; } return layoutSettings; } void SettingsDialog::insertLayoutInfoAtRow(int row, QString path, QString color, QString textColor, QString name, bool menu, bool disabledBorders, QStringList activities, bool locked) { QStandardItem *pathItem = new QStandardItem(path); QStandardItem *hiddenTextItem = new QStandardItem(); QStandardItem *colorItem = new QStandardItem(); colorItem->setSelectable(false); QStandardItem *nameItem = new QStandardItem(name); nameItem->setTextAlignment(Qt::AlignCenter); QStandardItem *menuItem = new QStandardItem(); menuItem->setEditable(false); menuItem->setSelectable(true); menuItem->setText(menu ? CheckMark : QString()); menuItem->setTextAlignment(Qt::AlignCenter); QStandardItem *bordersItem = new QStandardItem(); bordersItem->setEditable(false); bordersItem->setSelectable(true); bordersItem->setText(disabledBorders ? CheckMark : QString()); bordersItem->setTextAlignment(Qt::AlignCenter); QStandardItem *activitiesItem = new QStandardItem(activities.join(",")); QStandardItem *sharesItem = new QStandardItem(); QList items; items.append(pathItem); items.append(hiddenTextItem); items.append(colorItem); items.append(nameItem); items.append(menuItem); items.append(bordersItem); items.append(activitiesItem); items.append(sharesItem); if (row > m_model->rowCount() - 1) { m_model->appendRow(items); row = m_model->rowCount() - 1; qDebug() << "append row at:" << row << " rows:" << m_model->rowCount(); } else { m_model->insertRow(row, items); qDebug() << "insert row at:" << row << " rows:" << m_model->rowCount(); } m_model->setData(m_model->index(row, IDCOLUMN), path, Qt::DisplayRole); m_model->setData(m_model->index(row, COLORCOLUMN), color, Qt::BackgroundRole); m_model->setData(m_model->index(row, COLORCOLUMN), textColor, Qt::UserRole); QFont font; if (m_corona->layoutsManager()->synchronizer()->layout(name)) { font.setBold(true); } else { font.setBold(false); } if (path.startsWith("/tmp/")) { font.setItalic(true); } else { font.setItalic(false); } m_model->setData(m_model->index(row, NAMECOLUMN), QVariant(name), Qt::DisplayRole); m_model->setData(m_model->index(row, NAMECOLUMN), font, Qt::FontRole); m_model->setData(m_model->index(row, NAMECOLUMN), QVariant(locked), Qt::UserRole); m_model->setData(m_model->index(row, ACTIVITYCOLUMN), activities, Qt::UserRole); } void SettingsDialog::on_switchButton_clicked() { if (ui->buttonBox->button(QDialogButtonBox::Apply)->isEnabled()) { //! thus there are changes in the settings QString lName; QStringList lActivities; if (m_inMemoryButtons->checkedId() == Latte::Types::MultipleLayouts) { lName = m_model->data(m_model->index(ui->layoutsView->currentIndex().row(), NAMECOLUMN), Qt::DisplayRole).toString(); lActivities = m_model->data(m_model->index(ui->layoutsView->currentIndex().row(), ACTIVITYCOLUMN), Qt::UserRole).toStringList(); } apply(); if (!lName.isEmpty() && !lActivities.isEmpty()) { //! an activities-assigned layout is chosen and at the same time we are moving //! to multiple layouts state m_corona->layoutsManager()->switchToLayout(lName); } } else { QVariant value = m_model->data(m_model->index(ui->layoutsView->currentIndex().row(), NAMECOLUMN), Qt::DisplayRole); if (value.isValid()) { m_corona->layoutsManager()->switchToLayout(value.toString()); } else { qDebug() << "not valid layout"; } } updatePerLayoutButtonsState(); } void SettingsDialog::on_pauseButton_clicked() { ui->pauseButton->setEnabled(false); QString id = m_model->data(m_model->index(ui->layoutsView->currentIndex().row(), IDCOLUMN), Qt::DisplayRole).toString(); CentralLayout *layout = m_layouts[id]; if (layout) { m_corona->layoutsManager()->synchronizer()->pauseLayout(layout->name()); } } void SettingsDialog::layoutsChanged() { for (int i = 0; i < m_model->rowCount(); ++i) { QModelIndex nameIndex = m_model->index(i, NAMECOLUMN); QVariant value = m_model->data(nameIndex); if (value.isValid()) { QString name = value.toString(); QFont font; if (m_corona->layoutsManager()->currentLayoutName() == name) { font.setBold(true); // ui->layoutsView->selectRow(i); } else { Layout::GenericLayout *layout = m_corona->layoutsManager()->synchronizer()->layout(name); if (layout && (m_corona->layoutsManager()->memoryUsage() == Types::MultipleLayouts)) { font.setBold(true); } else { font.setBold(false); } } m_model->setData(nameIndex, font, Qt::FontRole); } } } void SettingsDialog::itemChanged(QStandardItem *item) { updatePerLayoutButtonsState(); if (item->column() == ACTIVITYCOLUMN) { //! recalculate the available activities recalculateAvailableActivities(); } else if (item->column() == NAMECOLUMN) { int currentRow = ui->layoutsView->currentIndex().row(); QString id = m_model->data(m_model->index(currentRow, IDCOLUMN), Qt::DisplayRole).toString(); QString name = m_model->data(m_model->index(currentRow, NAMECOLUMN), Qt::DisplayRole).toString(); QFont font = qvariant_cast(m_model->data(m_model->index(currentRow, NAMECOLUMN), Qt::FontRole)); if (m_corona->layoutsManager()->synchronizer()->layout(m_layouts[id]->name())) { font.setBold(true); } else { font.setBold(false); } if (m_layouts[id]->name() != name) { font.setItalic(true); } else { font.setItalic(false); } m_model->setData(m_model->index(currentRow, NAMECOLUMN), font, Qt::FontRole); } else if (item->column() == SHAREDCOLUMN) { updateSharedLayoutsStates(); } updateApplyButtonsState(); } void SettingsDialog::updateApplyButtonsState() { bool changed{false}; //! Ok, Apply Buttons if ((o_settings != currentSettings()) || (o_settingsLayouts != currentLayoutsSettings())) { changed = true; } if (changed) { ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); ui->buttonBox->button(QDialogButtonBox::Apply)->setEnabled(true); } else { //ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); ui->buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false); } //! RestoreDefaults Button if (ui->tabWidget->currentIndex() == 0) { //! Check Default layouts missing from layouts list bool layoutMissing{false}; for (const auto &preset : m_corona->layoutsManager()->presetsPaths()) { QString presetName = CentralLayout::layoutName(preset); QByteArray presetNameChars = presetName.toUtf8(); const char *prset_str = presetNameChars.data(); presetName = i18n(prset_str); if (!nameExistsInModel(presetName)) { layoutMissing = true; break; } } if (layoutMissing) { ui->buttonBox->button(QDialogButtonBox::RestoreDefaults)->setEnabled(true); } else { ui->buttonBox->button(QDialogButtonBox::RestoreDefaults)->setEnabled(false); } } else if (ui->tabWidget->currentIndex() == 1) { //! Defaults for general Latte settings if (!ui->autostartChkBox->isChecked() || ui->badges3DStyleChkBox->isChecked() || ui->metaPressChkBox->isChecked() || !ui->metaPressHoldChkBox->isChecked() || !ui->infoWindowChkBox->isChecked() || ui->noBordersForMaximizedChkBox->isChecked() || !ui->highSensitivityBtn->isChecked() || ui->screenTrackerSpinBox->value() != SCREENTRACKERDEFAULTVALUE || ui->outlineSpinBox->value() != OUTLINEDEFAULTWIDTH ) { ui->buttonBox->button(QDialogButtonBox::RestoreDefaults)->setEnabled(true); } else { ui->buttonBox->button(QDialogButtonBox::RestoreDefaults)->setEnabled(false); } } } void SettingsDialog::updatePerLayoutButtonsState() { int currentRow = ui->layoutsView->currentIndex().row(); QString id = m_model->data(m_model->index(currentRow, IDCOLUMN), Qt::DisplayRole).toString(); QString nameInModel = m_model->data(m_model->index(currentRow, NAMECOLUMN), Qt::DisplayRole).toString(); QString originalName = m_layouts.contains(id) ? m_layouts[id]->name() : ""; bool lockedInModel = m_model->data(m_model->index(currentRow, NAMECOLUMN), Qt::UserRole).toBool(); bool sharedInModel = !m_model->data(m_model->index(currentRow, SHAREDCOLUMN), Qt::UserRole).toStringList().isEmpty(); bool editable = !isActive(originalName) && !lockedInModel; //! Switch Button if (id.startsWith("/tmp/") || originalName != nameInModel) { ui->switchButton->setEnabled(false); } else { ui->switchButton->setEnabled(true); } //! Pause Button if (m_corona->layoutsManager()->memoryUsage() == Types::SingleLayout) { ui->pauseButton->setVisible(false); } else if (m_corona->layoutsManager()->memoryUsage() == Types::MultipleLayouts) { ui->pauseButton->setVisible(true); QStringList lActivities = m_model->data(m_model->index(currentRow, ACTIVITYCOLUMN), Qt::UserRole).toStringList(); Latte::CentralLayout *layout = m_layouts[id]; if (!lActivities.isEmpty() && layout && m_corona->layoutsManager()->synchronizer()->centralLayout(layout->name())) { ui->pauseButton->setEnabled(true); } else { ui->pauseButton->setEnabled(false); } } //! Remove Layout Button if (originalName != nameInModel || (originalName == m_corona->layoutsManager()->currentLayoutName()) || (m_corona->layoutsManager()->synchronizer()->centralLayout(originalName)) || lockedInModel) { ui->removeButton->setEnabled(false); } else { ui->removeButton->setEnabled(true); } //! Layout Locked Button if (lockedInModel) { ui->lockedButton->setChecked(true); } else { ui->lockedButton->setChecked(false); } //! Layout Shared Button if (sharedInModel) { ui->sharedButton->setChecked(true); } else { ui->sharedButton->setChecked(false); } if (editable) { m_editLayoutAction->setEnabled(true); } else { m_editLayoutAction->setEnabled(false); } } void SettingsDialog::updateSharedLayoutsStates() { bool inMultiple{inMultipleLayoutsLook()}; for (int i = 0; i < m_model->rowCount(); ++i) { QStringList shares = m_model->data(m_model->index(i, SHAREDCOLUMN), Qt::UserRole).toStringList(); if (shares.isEmpty() || !inMultiple) { QStandardItem *item = m_model->item(i, MENUCOLUMN); item->setEnabled(true); item = m_model->item(i, BORDERSCOLUMN); item->setEnabled(true); item = m_model->item(i, ACTIVITYCOLUMN); item->setEnabled(true); } else { QStandardItem *item = m_model->item(i, MENUCOLUMN); item->setEnabled(false); item = m_model->item(i, BORDERSCOLUMN); item->setEnabled(false); item = m_model->item(i, ACTIVITYCOLUMN); item->setEnabled(false); } //! refresh LayoutName QStandardItem *nameItem = m_model->item(i, NAMECOLUMN); nameItem->setEnabled(false); nameItem->setEnabled(true); } } void SettingsDialog::updateSharedLayoutsUiElements() { //! UI Elements that need to be enabled/disabled Latte::Types::LayoutsMemoryUsage inMemoryOption = static_cast(m_inMemoryButtons->checkedId()); if (inMemoryOption == Latte::Types::MultipleLayouts) { ui->layoutsView->setColumnHidden(SHAREDCOLUMN, false); ui->sharedButton->setVisible(true); //! column widths QStringList cWidths = m_corona->universalSettings()->layoutsColumnWidths(); if (cWidths.count()>=5) { ui->layoutsView->setColumnWidth(ACTIVITYCOLUMN, cWidths[4].toInt()); } } else { ui->layoutsView->setColumnHidden(SHAREDCOLUMN, true); ui->sharedButton->setVisible(false); } } void SettingsDialog::recalculateAvailableActivities() { QStringList tempActivities = m_corona->layoutsManager()->synchronizer()->activities(); for (int i = 0; i < m_model->rowCount(); ++i) { QStringList assigned = m_model->data(m_model->index(i, ACTIVITYCOLUMN), Qt::UserRole).toStringList(); for (const auto &activity : assigned) { if (tempActivities.contains(activity)) { tempActivities.removeAll(activity); } } } m_availableActivities = tempActivities; } bool SettingsDialog::dataAreAccepted() { for (int i = 0; i < m_model->rowCount(); ++i) { QString layout1 = m_model->data(m_model->index(i, NAMECOLUMN), Qt::DisplayRole).toString(); for (int j = i + 1; j < m_model->rowCount(); ++j) { QString temp = m_model->data(m_model->index(j, NAMECOLUMN), Qt::DisplayRole).toString(); //!same layout name exists again if (layout1 == temp) { auto msg = new QMessageBox(this); msg->setIcon(QMessageBox::Warning); msg->setWindowTitle(i18n("Layout Warning")); msg->setText(i18n("There are layouts with the same name, that is not permitted!!! Please update these names to re-apply the changes...")); msg->setStandardButtons(QMessageBox::Ok); connect(msg, &QMessageBox::finished, this, [ &, i, j](int result) { QItemSelectionModel::SelectionFlags flags = QItemSelectionModel::ClearAndSelect; QModelIndex indexBase = m_model->index(i, NAMECOLUMN); ui->layoutsView->selectionModel()->select(indexBase, flags); QModelIndex indexOccurence = m_model->index(j, NAMECOLUMN); ui->layoutsView->edit(indexOccurence); }); msg->open(); return false; } } } return true; } void SettingsDialog::showLayoutInformation() { int currentRow = ui->layoutsView->currentIndex().row(); QString id = m_model->data(m_model->index(currentRow, IDCOLUMN), Qt::DisplayRole).toString(); QString name = m_model->data(m_model->index(currentRow, NAMECOLUMN), Qt::DisplayRole).toString(); Layout::GenericLayout *genericActive= m_corona->layoutsManager()->synchronizer()->layout(m_layouts[id]->name()); Layout::GenericLayout *generic = genericActive ? genericActive : m_layouts[id]; auto msg = new QMessageBox(this); msg->setWindowTitle(name); msg->setText(generic->reportHtml(m_corona->screenPool())); msg->open(); } void SettingsDialog::showScreensInformation() { QList assignedScreens; for (int i = 0; i < m_model->rowCount(); ++i) { QString id = m_model->data(m_model->index(i, IDCOLUMN), Qt::DisplayRole).toString(); QString name = m_model->data(m_model->index(i, NAMECOLUMN), Qt::DisplayRole).toString(); Layout::GenericLayout *genericActive= m_corona->layoutsManager()->synchronizer()->layout(m_layouts[id]->name()); Layout::GenericLayout *generic = genericActive ? genericActive : m_layouts[id]; QList vScreens = generic->viewsScreens(); for (const int scrId : vScreens) { if (!assignedScreens.contains(scrId)) { assignedScreens << scrId; } } } auto msg = new QMessageBox(this); msg->setWindowTitle(i18n("Screens Information")); msg->setText(m_corona->screenPool()->reportHtml(assignedScreens)); msg->open(); } bool SettingsDialog::saveAllChanges() { if (!dataAreAccepted()) { return false; } //! Update universal settings Latte::Types::MouseSensitivity sensitivity = static_cast(m_mouseSensitivityButtons->checkedId()); bool autostart = ui->autostartChkBox->isChecked(); bool badges3DStyle = ui->badges3DStyleChkBox->isChecked(); bool forwardMetaPress = ui->metaPressChkBox->isChecked(); bool metaPressAndHold = ui->metaPressHoldChkBox->isChecked(); bool showInfoWindow = ui->infoWindowChkBox->isChecked(); bool noBordersForMaximized = ui->noBordersForMaximizedChkBox->isChecked(); m_corona->universalSettings()->setMouseSensitivity(sensitivity); m_corona->universalSettings()->setAutostart(autostart); m_corona->universalSettings()->setBadges3DStyle(badges3DStyle); - m_corona->universalSettings()->forwardMetaToLatte(forwardMetaPress); + m_corona->universalSettings()->kwin_forwardMetaToLatte(forwardMetaPress); m_corona->universalSettings()->setMetaPressAndHoldEnabled(metaPressAndHold); m_corona->universalSettings()->setShowInfoWindow(showInfoWindow); m_corona->universalSettings()->setCanDisableBorders(noBordersForMaximized); m_corona->universalSettings()->setScreenTrackerInterval(ui->screenTrackerSpinBox->value()); m_corona->themeExtended()->setOutlineWidth(ui->outlineSpinBox->value()); //! Update Layouts QStringList knownActivities = activities(); QTemporaryDir layoutTempDir; qDebug() << "Temporary Directory ::: " << layoutTempDir.path(); QStringList fromRenamePaths; QStringList toRenamePaths; QStringList toRenameNames; QString switchToLayout; QHash activeLayoutsToRename; //! remove layouts that have been removed from the user for (const auto &initLayout : m_initLayoutPaths) { if (!idExistsInModel(initLayout)) { QFile(initLayout).remove(); if (m_layouts.contains(initLayout)) { CentralLayout *removedLayout = m_layouts.take(initLayout); delete removedLayout; } } } for (int i = 0; i < m_model->rowCount(); ++i) { QString id = m_model->data(m_model->index(i, IDCOLUMN), Qt::DisplayRole).toString(); QString color = m_model->data(m_model->index(i, COLORCOLUMN), Qt::BackgroundRole).toString(); QString textColor = m_model->data(m_model->index(i, COLORCOLUMN), Qt::UserRole).toString(); QString name = m_model->data(m_model->index(i, NAMECOLUMN), Qt::DisplayRole).toString(); bool locked = m_model->data(m_model->index(i, NAMECOLUMN), Qt::UserRole).toBool(); bool menu = m_model->data(m_model->index(i, MENUCOLUMN), Qt::DisplayRole).toString() == CheckMark; bool disabledBorders = m_model->data(m_model->index(i, BORDERSCOLUMN), Qt::DisplayRole).toString() == CheckMark; QStringList lActivities = m_model->data(m_model->index(i, ACTIVITYCOLUMN), Qt::UserRole).toStringList(); QStringList cleanedActivities; //!update only activities that are valid for (const auto &activity : lActivities) { if (knownActivities.contains(activity)) { cleanedActivities.append(activity); } } //qDebug() << i << ". " << id << " - " << color << " - " << name << " - " << menu << " - " << lActivities; //! update the generic parts of the layouts Layout::GenericLayout *genericActive= m_corona->layoutsManager()->synchronizer()->layout(m_layouts[id]->name()); Layout::GenericLayout *generic = genericActive ? genericActive : m_layouts[id]; //! unlock read-only layout if (!generic->isWritable()) { generic->unlock(); } if (color.startsWith("/")) { //it is image file in such case if (color != generic->background()) { generic->setBackground(color); } if (generic->textColor() != textColor) { generic->setTextColor(textColor); } } else { if (color != generic->color()) { generic->setColor(color); generic->setBackground(QString()); generic->setTextColor(QString()); } } //! update only the Central-specific layout parts CentralLayout *centralActive= m_corona->layoutsManager()->synchronizer()->centralLayout(m_layouts[id]->name()); CentralLayout *central = centralActive ? centralActive : m_layouts[id]; if (central->showInMenu() != menu) { central->setShowInMenu(menu); } if (central->disableBordersForMaximizedWindows() != disabledBorders) { central->setDisableBordersForMaximizedWindows(disabledBorders); } if (central->activities() != cleanedActivities) { central->setActivities(cleanedActivities); } //! If the layout name changed OR the layout path is a temporary one if (generic->name() != name || (id.startsWith("/tmp/"))) { //! If the layout is Active in MultipleLayouts if (m_corona->layoutsManager()->memoryUsage() == Types::MultipleLayouts && generic->isActive()) { qDebug() << " Active Layout Should Be Renamed From : " << generic->name() << " TO :: " << name; activeLayoutsToRename[name] = generic; } QString tempFile = layoutTempDir.path() + "/" + QString(generic->name() + ".layout.latte"); qDebug() << "new temp file ::: " << tempFile; if ((m_corona->layoutsManager()->memoryUsage() == Types::SingleLayout) && (generic->name() == m_corona->layoutsManager()->currentLayoutName())) { switchToLayout = name; } generic = m_layouts.take(id); delete generic; QFile(id).rename(tempFile); fromRenamePaths.append(id); toRenamePaths.append(tempFile); toRenameNames.append(name); } } //! this is necessary in case two layouts have to swap names //! so we copy first the layouts in a temp directory and afterwards all //! together we move them in the official layout directory for (int i = 0; i < toRenamePaths.count(); ++i) { QString newFile = QDir::homePath() + "/.config/latte/" + toRenameNames[i] + ".layout.latte"; QFile(toRenamePaths[i]).rename(newFile); CentralLayout *nLayout = new CentralLayout(this, newFile); m_layouts[newFile] = nLayout; //! updating the #SETTINGSID in the model for the layout that was renamed for (int j = 0; j < m_model->rowCount(); ++j) { QString tId = m_model->data(m_model->index(j, IDCOLUMN), Qt::DisplayRole).toString(); if (tId == fromRenamePaths[i]) { m_model->setData(m_model->index(j, IDCOLUMN), newFile, Qt::DisplayRole); m_initLayoutPaths.append(newFile); QFont font = qvariant_cast(m_model->data(m_model->index(j, NAMECOLUMN), Qt::FontRole)); font.setItalic(false); m_model->setData(m_model->index(j, NAMECOLUMN), font, Qt::FontRole); } } } QString orphanedLayout; if (m_corona->layoutsManager()->memoryUsage() == Types::MultipleLayouts) { for (const auto &newLayoutName : activeLayoutsToRename.keys()) { Layout::GenericLayout *layout = activeLayoutsToRename[newLayoutName]; qDebug() << " Active Layout of Type: " << layout->type() << " Is Renamed From : " << activeLayoutsToRename[newLayoutName]->name() << " TO :: " << newLayoutName; layout->renameLayout(newLayoutName); if (layout->type() == Layout::Type::Central) { CentralLayout *central = qobject_cast(layout); if (central->activities().isEmpty()) { //! that means it is an active layout for orphaned Activities orphanedLayout = newLayoutName; } } //! broadcast the name change int row = rowForName(newLayoutName); QStandardItem *item = m_model->item(row, NAMECOLUMN); if (item) { emit itemChanged(item); } } } //! lock layouts in the end when the user has chosen it for (int i = 0; i < m_model->rowCount(); ++i) { QString id = m_model->data(m_model->index(i, IDCOLUMN), Qt::DisplayRole).toString(); QString name = m_model->data(m_model->index(i, NAMECOLUMN), Qt::DisplayRole).toString(); bool locked = m_model->data(m_model->index(i, NAMECOLUMN), Qt::UserRole).toBool(); Layout::GenericLayout *generic = m_corona->layoutsManager()->synchronizer()->layout(m_layouts[id]->name()); Layout::GenericLayout *layout = generic ? generic : m_layouts[id]; if (layout && locked && layout->isWritable()) { layout->lock(); } } //! update SharedLayouts that are Active syncActiveShares(); //! reload layouts in layoutsmanager m_corona->layoutsManager()->synchronizer()->loadLayouts(); //! send to layout manager in which layout to switch Latte::Types::LayoutsMemoryUsage inMemoryOption = static_cast(m_inMemoryButtons->checkedId()); if (m_corona->layoutsManager()->memoryUsage() != inMemoryOption) { Types::LayoutsMemoryUsage previousMemoryUsage = m_corona->layoutsManager()->memoryUsage(); m_corona->layoutsManager()->setMemoryUsage(inMemoryOption); QVariant value = m_model->data(m_model->index(ui->layoutsView->currentIndex().row(), NAMECOLUMN), Qt::DisplayRole); QString layoutName = value.toString(); m_corona->layoutsManager()->switchToLayout(layoutName, previousMemoryUsage); } else { if (!switchToLayout.isEmpty()) { m_corona->layoutsManager()->switchToLayout(switchToLayout); } else if (m_corona->layoutsManager()->memoryUsage() == Types::MultipleLayouts) { m_corona->layoutsManager()->synchronizer()->syncMultipleLayoutsToActivities(orphanedLayout); } } return true; } void SettingsDialog::syncActiveShares() { if (m_corona->layoutsManager()->memoryUsage() != Types::MultipleLayouts) { return; } QHash currentSharesIdMap; Layouts::SharesMap currentSharesNamesMap; for (int i = 0; i < m_model->rowCount(); ++i) { if (isShared(i)) { QString id = m_model->data(m_model->index(i, IDCOLUMN), Qt::DisplayRole).toString(); QString name = m_model->data(m_model->index(i, NAMECOLUMN), Qt::DisplayRole).toString(); QStringList shareIds = m_model->data(m_model->index(i, SHAREDCOLUMN), Qt::UserRole).toStringList(); QStringList shareNames; for (const auto &shareid : shareIds) { QString shareName = nameForId(shareid); shareNames << shareName; } currentSharesIdMap[id] = shareIds; currentSharesNamesMap[name] = shareNames; } } QStringList deprecatedShares; for (const auto &oldSharesIds : m_sharesMap) { for(const auto &oldId : oldSharesIds) { QString oldShareName = nameForId(oldId); if (!m_corona->layoutsManager()->synchronizer()->mapHasRecord(oldShareName, currentSharesNamesMap)) { deprecatedShares << oldShareName; } } } qDebug() << " CURRENT SHARES ID MAP :: " << currentSharesIdMap; m_corona->layoutsManager()->synchronizer()->syncActiveShares(currentSharesNamesMap, deprecatedShares); m_sharesMap.clear(); m_sharesMap = currentSharesIdMap; } void SettingsDialog::addActivityInCurrent(const QString &activityId) { int currentRow = ui->layoutsView->currentIndex().row(); QStringList activities = m_model->data(m_model->index(currentRow, ACTIVITYCOLUMN), Qt::UserRole).toStringList(); if (!activities.contains(activityId)) { activities << activityId; m_model->setData(m_model->index(currentRow, ACTIVITYCOLUMN), activities, Qt::UserRole); } } void SettingsDialog::removeActivityFromCurrent(const QString &activityId) { int currentRow = ui->layoutsView->currentIndex().row(); QStringList activities = m_model->data(m_model->index(currentRow, ACTIVITYCOLUMN), Qt::UserRole).toStringList(); if (activities.contains(activityId)) { activities.removeAll(activityId); m_model->setData(m_model->index(currentRow, ACTIVITYCOLUMN), activities, Qt::UserRole); } } void SettingsDialog::addShareInCurrent(const QString &layoutId) { int currentRow = ui->layoutsView->currentIndex().row(); QStringList shares = m_model->data(m_model->index(currentRow, SHAREDCOLUMN), Qt::UserRole).toStringList(); if (!shares.contains(layoutId)) { shares << layoutId; m_model->setData(m_model->index(currentRow, SHAREDCOLUMN), shares, Qt::UserRole); } } void SettingsDialog::removeShareFromCurrent(const QString &layoutId) { int currentRow = ui->layoutsView->currentIndex().row(); QStringList shares = m_model->data(m_model->index(currentRow, SHAREDCOLUMN), Qt::UserRole).toStringList(); if (shares.contains(layoutId)) { shares.removeAll(layoutId); m_model->setData(m_model->index(currentRow, SHAREDCOLUMN), shares, Qt::UserRole); } } bool SettingsDialog::idExistsInModel(QString id) { for (int i = 0; i < m_model->rowCount(); ++i) { QString rowId = m_model->data(m_model->index(i, IDCOLUMN), Qt::DisplayRole).toString(); if (rowId == id) { return true; } } return false; } bool SettingsDialog::nameExistsInModel(QString name) { for (int i = 0; i < m_model->rowCount(); ++i) { QString rowName = m_model->data(m_model->index(i, NAMECOLUMN), Qt::DisplayRole).toString(); if (rowName == name) { return true; } } return false; } bool SettingsDialog::inMultipleLayoutsLook() const { Latte::Types::LayoutsMemoryUsage inMemoryOption = static_cast(m_inMemoryButtons->checkedId()); return inMemoryOption == Latte::Types::MultipleLayouts; } bool SettingsDialog::isActive(QString layoutName) const { return (m_corona->layoutsManager()->synchronizer()->layout(layoutName) != nullptr); } bool SettingsDialog::isMenuCell(int column) const { return column == MENUCOLUMN; } bool SettingsDialog::isShared(int row) const { if (row >=0 ) { QStringList shares = m_model->data(m_model->index(row, SHAREDCOLUMN), Qt::UserRole).toStringList(); if (!shares.isEmpty()) { return true; } } return false; } int SettingsDialog::ascendingRowFor(QString name) { for (int i = 0; i < m_model->rowCount(); ++i) { QString rowName = m_model->data(m_model->index(i, NAMECOLUMN), Qt::DisplayRole).toString(); if (rowName.toUpper() > name.toUpper()) { return i; } } return m_model->rowCount(); } int SettingsDialog::rowForId(QString id) const { for (int i = 0; i < m_model->rowCount(); ++i) { QString rowId = m_model->data(m_model->index(i, IDCOLUMN), Qt::DisplayRole).toString(); if (rowId == id) { return i; } } return -1; } int SettingsDialog::rowForName(QString layoutName) const { for (int i = 0; i < m_model->rowCount(); ++i) { QString rowName = m_model->data(m_model->index(i, NAMECOLUMN), Qt::DisplayRole).toString(); if (rowName == layoutName) { return i; } } return -1; } QString SettingsDialog::idForRow(int row) const { return m_model->data(m_model->index(row, IDCOLUMN), Qt::DisplayRole).toString(); } QString SettingsDialog::nameForId(QString id) const { int row = rowForId(id); return m_model->data(m_model->index(row, NAMECOLUMN), Qt::DisplayRole).toString(); } QString SettingsDialog::uniqueTempDirectory() { QTemporaryDir tempDir; tempDir.setAutoRemove(false); m_tempDirectories.append(tempDir.path()); return tempDir.path(); } QString SettingsDialog::uniqueLayoutName(QString name) { int pos_ = name.lastIndexOf(QRegExp(QString("[-][0-9]+"))); if (nameExistsInModel(name) && pos_ > 0) { name = name.left(pos_); } int i = 2; QString namePart = name; while (nameExistsInModel(name)) { name = namePart + "-" + QString::number(i); i++; } return name; } }//end of namespace diff --git a/app/settings/universalsettings.cpp b/app/settings/universalsettings.cpp index 6565d506..9b5cab18 100644 --- a/app/settings/universalsettings.cpp +++ b/app/settings/universalsettings.cpp @@ -1,578 +1,619 @@ /* * Copyright 2017 Smith AR * Michail Vourlakos * * This file is part of Latte-Dock * * Latte-Dock is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * Latte-Dock 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 . */ #include "universalsettings.h" // local #include "../layouts/importer.h" #include "../layouts/manager.h" // Qt #include #include #include #include // KDE #include #include #define KWINMETAFORWARDTOLATTESTRING "org.kde.lattedock,/Latte,org.kde.LatteDock,activateLauncherMenu" #define KWINMETAFORWARDTOPLASMASTRING "org.kde.plasmashell,/PlasmaShell,org.kde.PlasmaShell,activateLauncherMenu" #define KWINCOLORSSCRIPT "kwin/scripts/lattewindowcolors" +#define KWINRC "/.config/kwinrc" namespace Latte { UniversalSettings::UniversalSettings(KSharedConfig::Ptr config, QObject *parent) : QObject(parent), m_config(config), m_universalGroup(KConfigGroup(config, QStringLiteral("UniversalSettings"))) { m_corona = qobject_cast(parent); connect(this, &UniversalSettings::badges3DStyleChanged, this, &UniversalSettings::saveConfig); connect(this, &UniversalSettings::canDisableBordersChanged, this, &UniversalSettings::saveConfig); connect(this, &UniversalSettings::currentLayoutNameChanged, this, &UniversalSettings::saveConfig); connect(this, &UniversalSettings::downloadWindowSizeChanged, this, &UniversalSettings::saveConfig); connect(this, &UniversalSettings::lastNonAssignedLayoutNameChanged, this, &UniversalSettings::saveConfig); connect(this, &UniversalSettings::launchersChanged, this, &UniversalSettings::saveConfig); connect(this, &UniversalSettings::layoutsColumnWidthsChanged, this, &UniversalSettings::saveConfig); connect(this, &UniversalSettings::layoutsMemoryUsageChanged, this, &UniversalSettings::saveConfig); connect(this, &UniversalSettings::layoutsWindowSizeChanged, this, &UniversalSettings::saveConfig); connect(this, &UniversalSettings::metaPressAndHoldEnabledChanged, this, &UniversalSettings::saveConfig); connect(this, &UniversalSettings::mouseSensitivityChanged, this, &UniversalSettings::saveConfig); connect(this, &UniversalSettings::screenTrackerIntervalChanged, this, &UniversalSettings::saveConfig); connect(this, &UniversalSettings::showInfoWindowChanged, this, &UniversalSettings::saveConfig); connect(this, &UniversalSettings::versionChanged, this, &UniversalSettings::saveConfig); connect(this, &UniversalSettings::screenScalesChanged, this, &UniversalSettings::saveScalesConfig); connect(qGuiApp, &QGuiApplication::screenAdded, this, &UniversalSettings::screensCountChanged); connect(qGuiApp, &QGuiApplication::screenRemoved, this, &UniversalSettings::screensCountChanged); } UniversalSettings::~UniversalSettings() { saveConfig(); cleanupSettings(); } void UniversalSettings::load() { //! check if user has set the autostart option bool autostartUserSet = m_universalGroup.readEntry("userConfiguredAutostart", false); if (!autostartUserSet && !autostart()) { setAutostart(true); } //! init screen scales m_screenScalesGroup = m_universalGroup.group("ScreenScales"); //! load configuration loadConfig(); //! Track KWin Colors Script Presence updateColorsScriptIsPresent(); QStringList colorsScriptPaths = Layouts::Importer::standardPathsFor(KWINCOLORSSCRIPT); for(auto path: colorsScriptPaths) { KDirWatch::self()->addDir(path); } - connect(KDirWatch::self(), &KDirWatch::created, this, &UniversalSettings::colorsScriptChanged); - connect(KDirWatch::self(), &KDirWatch::deleted, this, &UniversalSettings::colorsScriptChanged); + //! Track KWin rc options + const QString kwinrcFilePath = QDir::homePath() + KWINRC; + KDirWatch::self()->addFile(kwinrcFilePath); + recoverKWinOptions(); + + connect(KDirWatch::self(), &KDirWatch::created, this, &UniversalSettings::trackedFileChanged); + connect(KDirWatch::self(), &KDirWatch::deleted, this, &UniversalSettings::trackedFileChanged); + connect(KDirWatch::self(), &KDirWatch::dirty, this, &UniversalSettings::trackedFileChanged); //! this is needed to inform globalshortcuts to update its modifiers tracking emit metaPressAndHoldEnabledChanged(); } bool UniversalSettings::showInfoWindow() const { return m_showInfoWindow; } void UniversalSettings::setShowInfoWindow(bool show) { if (m_showInfoWindow == show) { return; } m_showInfoWindow = show; emit showInfoWindowChanged(); } int UniversalSettings::version() const { return m_version; } void UniversalSettings::setVersion(int ver) { if (m_version == ver) { return; } m_version = ver; emit versionChanged(); } int UniversalSettings::screenTrackerInterval() const { return m_screenTrackerInterval; } void UniversalSettings::setScreenTrackerInterval(int duration) { if (m_screenTrackerInterval == duration) { return; } m_screenTrackerInterval = duration; emit screenTrackerIntervalChanged(); } QString UniversalSettings::currentLayoutName() const { return m_currentLayoutName; } void UniversalSettings::setCurrentLayoutName(QString layoutName) { if (m_currentLayoutName == layoutName) { return; } m_currentLayoutName = layoutName; emit currentLayoutNameChanged(); } QString UniversalSettings::lastNonAssignedLayoutName() const { return m_lastNonAssignedLayoutName; } void UniversalSettings::setLastNonAssignedLayoutName(QString layoutName) { if (m_lastNonAssignedLayoutName == layoutName) { return; } m_lastNonAssignedLayoutName = layoutName; emit lastNonAssignedLayoutNameChanged(); } QSize UniversalSettings::downloadWindowSize() const { return m_downloadWindowSize; } void UniversalSettings::setDownloadWindowSize(QSize size) { if (m_downloadWindowSize == size) { return; } m_downloadWindowSize = size; emit downloadWindowSizeChanged(); } QSize UniversalSettings::layoutsWindowSize() const { return m_layoutsWindowSize; } void UniversalSettings::setLayoutsWindowSize(QSize size) { if (m_layoutsWindowSize == size) { return; } m_layoutsWindowSize = size; emit layoutsWindowSizeChanged(); } QStringList UniversalSettings::layoutsColumnWidths() const { return m_layoutsColumnWidths; } void UniversalSettings::setLayoutsColumnWidths(QStringList widths) { if (m_layoutsColumnWidths == widths) { return; } m_layoutsColumnWidths = widths; emit layoutsColumnWidthsChanged(); } QStringList UniversalSettings::launchers() const { return m_launchers; } void UniversalSettings::setLaunchers(QStringList launcherList) { if (m_launchers == launcherList) { return; } m_launchers = launcherList; emit launchersChanged(); } bool UniversalSettings::autostart() const { QFile autostartFile(QDir::homePath() + "/.config/autostart/org.kde.latte-dock.desktop"); return autostartFile.exists(); } void UniversalSettings::setAutostart(bool state) { //! remove old autostart file QFile oldAutostartFile(QDir::homePath() + "/.config/autostart/latte-dock.desktop"); if (oldAutostartFile.exists()) { oldAutostartFile.remove(); } //! end of removal of old autostart file QFile autostartFile(QDir::homePath() + "/.config/autostart/org.kde.latte-dock.desktop"); QFile metaFile(Layouts::Importer::standardPath("applications", false)+"/org.kde.latte-dock.desktop"); if (!state && autostartFile.exists()) { //! the first time that the user disables the autostart, this is recorded //! and from now own it will not be recreated it in the beginning if (!m_universalGroup.readEntry("userConfiguredAutostart", false)) { m_universalGroup.writeEntry("userConfiguredAutostart", true); } autostartFile.remove(); emit autostartChanged(); } else if (state && metaFile.exists()) { //! check if autostart folder exists and create otherwise QDir autostartDir(QDir::homePath() + "/.config/autostart"); if (!autostartDir.exists()) { QDir configDir(QDir::homePath() + "/.config"); configDir.mkdir("autostart"); } metaFile.copy(autostartFile.fileName()); //! I haven't added the flag "OnlyShowIn=KDE;" into the autostart file //! because I fall onto a Plasma 5.8 case that this flag //! didn't let the plasma desktop to start emit autostartChanged(); } } bool UniversalSettings::badges3DStyle() const { return m_badges3DStyle; } void UniversalSettings::setBadges3DStyle(bool enable) { if (m_badges3DStyle == enable) { return; } m_badges3DStyle = enable; emit badges3DStyleChanged(); } bool UniversalSettings::canDisableBorders() const { return m_canDisableBorders; } void UniversalSettings::setCanDisableBorders(bool enable) { if (m_canDisableBorders == enable) { return; } m_canDisableBorders = enable; emit canDisableBordersChanged(); } bool UniversalSettings::colorsScriptIsPresent() const { return m_colorsScriptIsPresent; } void UniversalSettings::setColorsScriptIsPresent(bool present) { if (m_colorsScriptIsPresent == present) { return; } m_colorsScriptIsPresent = present; emit colorsScriptIsPresentChanged(); } void UniversalSettings::updateColorsScriptIsPresent() { + qDebug() << "Updating Latte Colors Script presence..."; + setColorsScriptIsPresent(!Layouts::Importer::standardPath(KWINCOLORSSCRIPT).isEmpty()); } -void UniversalSettings::colorsScriptChanged(const QString &file) -{ - if (!file.endsWith(KWINCOLORSSCRIPT)) { - return; +void UniversalSettings::trackedFileChanged(const QString &file) +{ + if (file.endsWith(KWINCOLORSSCRIPT)) { + updateColorsScriptIsPresent(); } - updateColorsScriptIsPresent(); -} - -bool UniversalSettings::metaForwardedToLatte() const -{ - return kwin_metaForwardedToLatte(); + if (file.endsWith(KWINRC)) { + recoverKWinOptions(); + } } -void UniversalSettings::forwardMetaToLatte(bool forward) +bool UniversalSettings::kwin_metaForwardedToLatte() const { - kwin_forwardMetaToLatte(forward); + return m_kwinMetaForwardedToLatte; } -bool UniversalSettings::kwin_metaForwardedToLatte() const +bool UniversalSettings::kwin_borderlessMaximizedWindowsEnabled() const { - QProcess process; - process.start("kreadconfig5 --file kwinrc --group ModifierOnlyShortcuts --key Meta"); - process.waitForFinished(); - QString output(process.readAllStandardOutput()); - - output = output.remove("\n"); - - return (output == KWINMETAFORWARDTOLATTESTRING); + return m_kwinBorderlessMaximizedWindows; } void UniversalSettings::kwin_forwardMetaToLatte(bool forward) { - if (kwin_metaForwardedToLatte() == forward) { + if (m_kwinMetaForwardedToLatte == forward) { return; } QProcess process; QStringList parameters; parameters << "--file" << "kwinrc" << "--group" << "ModifierOnlyShortcuts" << "--key" << "Meta"; if (forward) { parameters << KWINMETAFORWARDTOLATTESTRING; } else { parameters << KWINMETAFORWARDTOPLASMASTRING; } process.start("kwriteconfig5", parameters); process.waitForFinished(); QDBusInterface iface("org.kde.KWin", "/KWin", "", QDBusConnection::sessionBus()); if (iface.isValid()) { iface.call("reconfigure"); } } +void UniversalSettings::kwin_setDisabledMaximizedBorders(bool disable) +{ + if (m_kwinBorderlessMaximizedWindows == disable) { + return; + } + + QString disableText = disable ? "true" : "false"; + + QProcess process; + QString commandStr = "kwriteconfig5 --file kwinrc --group Windows --key BorderlessMaximizedWindows --type bool " + disableText; + process.start(commandStr); + process.waitForFinished(); + + QDBusInterface iface("org.kde.KWin", "/KWin", "", QDBusConnection::sessionBus()); + + if (iface.isValid()) { + iface.call("reconfigure"); + } +} + +void UniversalSettings::recoverKWinOptions() +{ + qDebug() << "kwinrc: recovering values..."; + + //! Meta forwarded to Latte option + QProcess process; + process.start("kreadconfig5 --file kwinrc --group ModifierOnlyShortcuts --key Meta"); + process.waitForFinished(); + QString output(process.readAllStandardOutput()); + output = output.remove("\n"); + + m_kwinMetaForwardedToLatte = (output == KWINMETAFORWARDTOLATTESTRING); + + //! BorderlessMaximizedWindows option + process.start("kreadconfig5 --file kwinrc --group Windows --key BorderlessMaximizedWindows"); + process.waitForFinished(); + output = process.readAllStandardOutput(); + output = output.remove("\n"); + m_kwinBorderlessMaximizedWindows = (output == "true"); +} + + bool UniversalSettings::metaPressAndHoldEnabled() const { return m_metaPressAndHoldEnabled; } void UniversalSettings::setMetaPressAndHoldEnabled(bool enabled) { if (m_metaPressAndHoldEnabled == enabled) { return; } m_metaPressAndHoldEnabled = enabled; emit metaPressAndHoldEnabledChanged(); } Types::LayoutsMemoryUsage UniversalSettings::layoutsMemoryUsage() const { return m_memoryUsage; } void UniversalSettings::setLayoutsMemoryUsage(Types::LayoutsMemoryUsage layoutsMemoryUsage) { if (m_memoryUsage == layoutsMemoryUsage) { return; } m_memoryUsage = layoutsMemoryUsage; emit layoutsMemoryUsageChanged(); } Types::MouseSensitivity UniversalSettings::mouseSensitivity() const { return m_mouseSensitivity; } void UniversalSettings::setMouseSensitivity(Types::MouseSensitivity sensitivity) { if (m_mouseSensitivity == sensitivity) { return; } m_mouseSensitivity = sensitivity; emit mouseSensitivityChanged(); } float UniversalSettings::screenWidthScale(QString screenName) const { if (!m_screenScales.contains(screenName)) { return 1; } return m_screenScales[screenName].first; } float UniversalSettings::screenHeightScale(QString screenName) const { if (!m_screenScales.contains(screenName)) { return 1; } return m_screenScales[screenName].second; } void UniversalSettings::setScreenScales(QString screenName, float widthScale, float heightScale) { if (!m_screenScales.contains(screenName)) { m_screenScales[screenName].first = widthScale; m_screenScales[screenName].second = heightScale; } else { if (m_screenScales[screenName].first == widthScale && m_screenScales[screenName].second == heightScale) { return; } m_screenScales[screenName].first = widthScale; m_screenScales[screenName].second = heightScale; } emit screenScalesChanged(); } void UniversalSettings::loadConfig() { m_version = m_universalGroup.readEntry("version", 1); m_badges3DStyle = m_universalGroup.readEntry("badges3DStyle", false); m_canDisableBorders = m_universalGroup.readEntry("canDisableBorders", false); m_currentLayoutName = m_universalGroup.readEntry("currentLayout", QString()); m_downloadWindowSize = m_universalGroup.readEntry("downloadWindowSize", QSize(800, 550)); m_lastNonAssignedLayoutName = m_universalGroup.readEntry("lastNonAssignedLayout", QString()); m_layoutsWindowSize = m_universalGroup.readEntry("layoutsWindowSize", QSize(700, 450)); m_layoutsColumnWidths = m_universalGroup.readEntry("layoutsColumnWidths", QStringList()); m_launchers = m_universalGroup.readEntry("launchers", QStringList()); m_metaPressAndHoldEnabled = m_universalGroup.readEntry("metaPressAndHoldEnabled", true); m_screenTrackerInterval = m_universalGroup.readEntry("screenTrackerInterval", 2500); m_showInfoWindow = m_universalGroup.readEntry("showInfoWindow", true); m_memoryUsage = static_cast(m_universalGroup.readEntry("memoryUsage", (int)Types::SingleLayout)); m_mouseSensitivity = static_cast(m_universalGroup.readEntry("mouseSensitivity", (int)Types::HighSensitivity)); loadScalesConfig(); } void UniversalSettings::saveConfig() { m_universalGroup.writeEntry("version", m_version); m_universalGroup.writeEntry("badges3DStyle", m_badges3DStyle); m_universalGroup.writeEntry("canDisableBorders", m_canDisableBorders); m_universalGroup.writeEntry("currentLayout", m_currentLayoutName); m_universalGroup.writeEntry("downloadWindowSize", m_downloadWindowSize); m_universalGroup.writeEntry("lastNonAssignedLayout", m_lastNonAssignedLayoutName); m_universalGroup.writeEntry("layoutsWindowSize", m_layoutsWindowSize); m_universalGroup.writeEntry("layoutsColumnWidths", m_layoutsColumnWidths); m_universalGroup.writeEntry("launchers", m_launchers); m_universalGroup.writeEntry("metaPressAndHoldEnabled", m_metaPressAndHoldEnabled); m_universalGroup.writeEntry("screenTrackerInterval", m_screenTrackerInterval); m_universalGroup.writeEntry("showInfoWindow", m_showInfoWindow); m_universalGroup.writeEntry("memoryUsage", (int)m_memoryUsage); m_universalGroup.writeEntry("mouseSensitivity", (int)m_mouseSensitivity); m_universalGroup.sync(); } void UniversalSettings::cleanupSettings() { KConfigGroup containments = KConfigGroup(m_config, QStringLiteral("Containments")); containments.deleteGroup(); containments.sync(); } QString UniversalSettings::splitterIconPath() { return m_corona->kPackage().filePath("splitter"); } QString UniversalSettings::trademarkIconPath() { return m_corona->kPackage().filePath("trademark"); } QQmlListProperty UniversalSettings::screens() { return QQmlListProperty(this, nullptr, &countScreens, &atScreens); } int UniversalSettings::countScreens(QQmlListProperty *property) { Q_UNUSED(property) return qGuiApp->screens().count(); } QScreen *UniversalSettings::atScreens(QQmlListProperty *property, int index) { Q_UNUSED(property) return qGuiApp->screens().at(index); } void UniversalSettings::loadScalesConfig() { for (const auto &screenName : m_screenScalesGroup.keyList()) { QString scalesStr = m_screenScalesGroup.readEntry(screenName, QString()); QStringList scales = scalesStr.split(";"); if (scales.count() == 2) { m_screenScales[screenName] = qMakePair(scales[0].toFloat(), scales[1].toFloat()); } } } void UniversalSettings::saveScalesConfig() { for (const auto &screenName : m_screenScales.keys()) { QStringList scales; scales << QString::number(m_screenScales[screenName].first) << QString::number(m_screenScales[screenName].second); m_screenScalesGroup.writeEntry(screenName, scales.join(";")); } m_screenScalesGroup.sync(); } } diff --git a/app/settings/universalsettings.h b/app/settings/universalsettings.h index 01caf1c6..e3fb2fb2 100644 --- a/app/settings/universalsettings.h +++ b/app/settings/universalsettings.h @@ -1,212 +1,217 @@ /* * Copyright 2017 Smith AR * Michail Vourlakos * * This file is part of Latte-Dock * * Latte-Dock is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * Latte-Dock 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 . */ #ifndef UNIVERSALSETTINGS_H #define UNIVERSALSETTINGS_H // local #include "../lattecorona.h" #include "../liblatte2/types.h" // Qt #include #include #include #include #include #include #include // KDE #include #include namespace Latte { namespace Layouts { class Manager; } } namespace Latte { //width_scale, height_scale typedef QPair ScreenScales; //! This class holds all the settings that are universally available //! independent of layouts class UniversalSettings : public QObject { Q_OBJECT Q_PROPERTY(bool autostart READ autostart WRITE setAutostart NOTIFY autostartChanged) Q_PROPERTY(bool badges3DStyle READ badges3DStyle WRITE setBadges3DStyle NOTIFY badges3DStyleChanged) Q_PROPERTY(bool colorsScriptIsPresent READ colorsScriptIsPresent NOTIFY colorsScriptIsPresentChanged) Q_PROPERTY(bool showInfoWindow READ showInfoWindow WRITE setShowInfoWindow NOTIFY showInfoWindowChanged) Q_PROPERTY(QString currentLayoutName READ currentLayoutName WRITE setCurrentLayoutName NOTIFY currentLayoutNameChanged) Q_PROPERTY(QStringList launchers READ launchers WRITE setLaunchers NOTIFY launchersChanged) Q_PROPERTY(Latte::Types::MouseSensitivity mouseSensitivity READ mouseSensitivity WRITE setMouseSensitivity NOTIFY mouseSensitivityChanged) Q_PROPERTY(QQmlListProperty screens READ screens) public: UniversalSettings(KSharedConfig::Ptr config, QObject *parent = nullptr); ~UniversalSettings() override; void load(); bool autostart() const; void setAutostart(bool state); bool badges3DStyle() const; void setBadges3DStyle(bool enable); bool canDisableBorders() const; void setCanDisableBorders(bool enable); bool colorsScriptIsPresent() const; - bool metaForwardedToLatte() const; - void forwardMetaToLatte(bool forward); + bool kwin_metaForwardedToLatte() const; + void kwin_forwardMetaToLatte(bool forward); + + bool kwin_borderlessMaximizedWindowsEnabled() const; + void kwin_setDisabledMaximizedBorders(bool disable); bool metaPressAndHoldEnabled() const; void setMetaPressAndHoldEnabled(bool enabled); bool showInfoWindow() const; void setShowInfoWindow(bool show); int version() const; void setVersion(int ver); int screenTrackerInterval() const; void setScreenTrackerInterval(int duration); QString currentLayoutName() const; void setCurrentLayoutName(QString layoutName); QString lastNonAssignedLayoutName() const; void setLastNonAssignedLayoutName(QString layoutName); QSize downloadWindowSize() const; void setDownloadWindowSize(QSize size); QSize layoutsWindowSize() const; void setLayoutsWindowSize(QSize size); QStringList layoutsColumnWidths() const; void setLayoutsColumnWidths(QStringList widths); QStringList launchers() const; void setLaunchers(QStringList launcherList); Types::MouseSensitivity mouseSensitivity() const; void setMouseSensitivity(Types::MouseSensitivity sensitivity); QQmlListProperty screens(); static int countScreens(QQmlListProperty *property); //! is needed by screens() static QScreen *atScreens(QQmlListProperty *property, int index); //! is needed by screens() public slots: Q_INVOKABLE QString splitterIconPath(); Q_INVOKABLE QString trademarkIconPath(); Q_INVOKABLE float screenWidthScale(QString screenName) const; Q_INVOKABLE float screenHeightScale(QString screenName) const; Q_INVOKABLE void setScreenScales(QString screenName, float widthScale, float heightScale); signals: void autostartChanged(); void badges3DStyleChanged(); void canDisableBordersChanged(); void colorsScriptIsPresentChanged(); void currentLayoutNameChanged(); void downloadWindowSizeChanged(); void lastNonAssignedLayoutNameChanged(); void layoutsColumnWidthsChanged(); void layoutsWindowSizeChanged(); void launchersChanged(); void layoutsMemoryUsageChanged(); void metaPressAndHoldEnabledChanged(); void mouseSensitivityChanged(); void screensCountChanged(); void screenScalesChanged(); void screenTrackerIntervalChanged(); void showInfoWindowChanged(); void versionChanged(); private slots: void loadConfig(); void loadScalesConfig(); void saveConfig(); void saveScalesConfig(); + void recoverKWinOptions(); void updateColorsScriptIsPresent(); - void colorsScriptChanged(const QString &file); + void trackedFileChanged(const QString &file); private: void cleanupSettings(); - bool kwin_metaForwardedToLatte() const; - void kwin_forwardMetaToLatte(bool forward); - void setColorsScriptIsPresent(bool present); Types::LayoutsMemoryUsage layoutsMemoryUsage() const; void setLayoutsMemoryUsage(Types::LayoutsMemoryUsage layoutsMemoryUsage); private: bool m_badges3DStyle{false}; bool m_canDisableBorders{false}; bool m_colorsScriptIsPresent{false}; bool m_metaPressAndHoldEnabled{true}; bool m_showInfoWindow{true}; + //!kwinrc tracking + bool m_kwinMetaForwardedToLatte{false}; + bool m_kwinBorderlessMaximizedWindows{false}; + //when there isnt a version it is an old universal file int m_version{1}; int m_screenTrackerInterval{2500}; QString m_currentLayoutName; QString m_lastNonAssignedLayoutName; QSize m_downloadWindowSize{800, 550}; QSize m_layoutsWindowSize{700, 450}; QStringList m_layoutsColumnWidths; QStringList m_launchers; Types::LayoutsMemoryUsage m_memoryUsage; Types::MouseSensitivity m_mouseSensitivity{Types::HighSensitivity}; //! ScreenName, QHash m_screenScales; QPointer m_corona; KConfigGroup m_screenScalesGroup; KConfigGroup m_universalGroup; KSharedConfig::Ptr m_config; friend class Layouts::Manager; friend class Latte::Corona; }; } #endif //UNIVERSALSETTINGS_H diff --git a/app/shortcuts/globalshortcuts.cpp b/app/shortcuts/globalshortcuts.cpp index 96643744..c57ce992 100644 --- a/app/shortcuts/globalshortcuts.cpp +++ b/app/shortcuts/globalshortcuts.cpp @@ -1,797 +1,797 @@ /* * Copyright 2016 Smith AR * Michail Vourlakos * * This file is part of Latte-Dock * * Latte-Dock is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * Latte-Dock 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 . */ #include "globalshortcuts.h" // local #include "modifiertracker.h" #include "shortcutstracker.h" #include "../lattecorona.h" #include "../layout/centrallayout.h" #include "../layouts/manager.h" #include "../layouts/synchronizer.h" #include "../settings/universalsettings.h" #include "../view/view.h" // C++ #include // Qt #include #include #include #include #include // KDE #include #include #include #include // Plasma #include #include namespace Latte { const int APPLETEXECUTIONDELAY = 400; GlobalShortcuts::GlobalShortcuts(QObject *parent) : QObject(parent) { m_corona = qobject_cast(parent); m_modifierTracker = new ShortcutsPart::ModifierTracker(this); m_shortcutsTracker = new ShortcutsPart::ShortcutsTracker(this); if (m_corona) { init(); } m_hideViewsTimer.setSingleShot(true); if (QX11Info::isPlatformX11()) { //in X11 the timer is a poller that checks to see if the modifier keys //from user global shortcut have been released m_hideViewsTimer.setInterval(300); } else { //on wayland in acting just as simple timer that hides the view afterwards m_hideViewsTimer.setInterval(2500); } connect(&m_hideViewsTimer, &QTimer::timeout, this, &GlobalShortcuts::hideViewsTimerSlot); } GlobalShortcuts::~GlobalShortcuts() { if (m_modifierTracker) { m_modifierTracker->deleteLater(); } if (m_shortcutsTracker) { m_shortcutsTracker->deleteLater(); } } void GlobalShortcuts::init() { KActionCollection *generalActions = new KActionCollection(m_corona); //show-hide the main view in the primary screen QAction *showAction = generalActions->addAction(QStringLiteral("show latte view")); showAction->setText(i18n("Show Latte Dock/Panel")); showAction->setShortcut(QKeySequence(Qt::META + '`')); KGlobalAccel::setGlobalShortcut(showAction, QKeySequence(Qt::META + '`')); connect(showAction, &QAction::triggered, this, [this]() { showViews(); }); //show-cycle between Latte settings windows QAction *settingsAction = generalActions->addAction(QStringLiteral("show view settings")); settingsAction->setText(i18n("Cycle Through Dock/Panel Settings Windows")); KGlobalAccel::setGlobalShortcut(settingsAction, QKeySequence(Qt::META + Qt::Key_A)); connect(settingsAction, &QAction::triggered, this, [this] { m_modifierTracker->cancelMetaPressed(); showSettings(); }); //show the layouts editor QAction *layoutsAction = generalActions->addAction(QStringLiteral("show latte global settings")); layoutsAction->setText(i18n("Show Latte Global Settings")); layoutsAction->setShortcut(QKeySequence(Qt::META + Qt::Key_W)); KGlobalAccel::setGlobalShortcut(layoutsAction, QKeySequence(Qt::META + Qt::Key_W)); connect(layoutsAction, &QAction::triggered, this, [this]() { m_modifierTracker->cancelMetaPressed(); m_corona->layoutsManager()->showLatteSettingsDialog(Types::LayoutPage); }); KActionCollection *taskbarActions = new KActionCollection(m_corona); //activate actions [1-9] for (int i = 1; i < 10; ++i) { const int entryNumber = i; const Qt::Key key = static_cast(Qt::Key_0 + i); QAction *action = taskbarActions->addAction(QStringLiteral("activate entry %1").arg(QString::number(entryNumber))); action->setText(i18n("Activate Entry %1", entryNumber)); action->setShortcut(QKeySequence(Qt::META + key)); KGlobalAccel::setGlobalShortcut(action, QKeySequence(Qt::META + key)); connect(action, &QAction::triggered, this, [this, i] { // qDebug() << "meta action..."; m_modifierTracker->cancelMetaPressed(); activateEntry(i, static_cast(Qt::META)); }); } //! Array that is used to register correctly actions for task index>=10 and <19 std::array keysAboveTen{ Qt::Key_0, Qt::Key_Z, Qt::Key_X, Qt::Key_C, Qt::Key_V, Qt::Key_B, Qt::Key_N, Qt::Key_M, Qt::Key_Comma, Qt::Key_Period }; //activate actions [10-19] for (int i = 10; i < 20; ++i) { QAction *action = taskbarActions->addAction(QStringLiteral("activate entry %1").arg(QString::number(i))); action->setText(i18n("Activate Entry %1", i)); action->setShortcut(QKeySequence(Qt::META + keysAboveTen[i - 10])); KGlobalAccel::setGlobalShortcut(action, QKeySequence(Qt::META + keysAboveTen[i - 10])); connect(action, &QAction::triggered, this, [this, i] { m_modifierTracker->cancelMetaPressed(); activateEntry(i, static_cast(Qt::META)); }); } //new instance actions [1-9] for (int i = 1; i < 10; ++i) { const int entryNumber = i; const Qt::Key key = static_cast(Qt::Key_0 + i); QAction *action = taskbarActions->addAction(QStringLiteral("new instance for entry %1").arg(QString::number(entryNumber))); action->setText(i18n("New Instance for Entry %1", entryNumber)); KGlobalAccel::setGlobalShortcut(action, QKeySequence(Qt::META + Qt::CTRL + key)); connect(action, &QAction::triggered, this, [this, i] { // qDebug() << "meta + ctrl + action..."; m_modifierTracker->cancelMetaPressed(); activateEntry(i, static_cast(Qt::CTRL)); }); } //new instance actions [10-19] for (int i = 10; i < 20; ++i) { QAction *action = taskbarActions->addAction(QStringLiteral("new instance for entry %1").arg(QString::number(i))); action->setText(i18n("New Instance for Entry %1", i)); KGlobalAccel::setGlobalShortcut(action, QKeySequence(Qt::META + Qt::CTRL + keysAboveTen[i - 10])); connect(action, &QAction::triggered, this, [this, i] { m_modifierTracker->cancelMetaPressed(); activateEntry(i, static_cast(Qt::CTRL)); }); } m_singleMetaAction = new QAction(this); m_singleMetaAction->setShortcut(QKeySequence(Qt::META)); connect(m_corona->universalSettings(), &UniversalSettings::metaPressAndHoldEnabledChanged , this, [&]() { if (!m_corona->universalSettings()->metaPressAndHoldEnabled()) { m_modifierTracker->blockModifierTracking(Qt::Key_Super_L); m_modifierTracker->blockModifierTracking(Qt::Key_Super_R); } else { m_modifierTracker->unblockModifierTracking(Qt::Key_Super_L); m_modifierTracker->unblockModifierTracking(Qt::Key_Super_R); } }); //display shortcut badges while holding Meta connect(m_modifierTracker, &ShortcutsPart::ModifierTracker::metaModifierPressed, this, [&]() { m_metaShowedViews = true; showViews(); }); } ShortcutsPart::ShortcutsTracker *GlobalShortcuts::shortcutsTracker() const { return m_shortcutsTracker; } //! Activate launcher menu through dbus interface void GlobalShortcuts::activateLauncherMenu() { if (m_metaShowedViews) { return; } QList sortedViews; CentralLayout *currentLayout = m_corona->layoutsManager()->currentLayout(); if (currentLayout) { sortedViews = currentLayout->sortedLatteViews(); } for (const auto view : sortedViews) { const auto applets = view->containment()->applets(); for (auto applet : applets) { const auto provides = applet->kPackage().metadata().value(QStringLiteral("X-Plasma-Provides")); if (provides.contains(QLatin1String("org.kde.plasma.launchermenu"))) { if (view->visibility()->isHidden()) { if (!m_hideViews.contains(view)) { m_hideViews.append(view); } m_lastInvokedAction = m_singleMetaAction; view->visibility()->setBlockHiding(true); //! delay the execution in order to show first the view QTimer::singleShot(APPLETEXECUTIONDELAY, [this, view, applet]() { view->toggleAppletExpanded(applet->id()); }); m_hideViewsTimer.start(); } else { view->toggleAppletExpanded(applet->id()); } return; } } } } bool GlobalShortcuts::activatePlasmaTaskManagerEntryAtContainment(const Plasma::Containment *c, int index, Qt::Key modifier) { const auto &applets = c->applets(); for (auto *applet : applets) { const auto &provides = KPluginMetaData::readStringList(applet->pluginMetaData().rawData(), QStringLiteral("X-Plasma-Provides")); if (provides.contains(QLatin1String("org.kde.plasma.multitasking"))) { if (QQuickItem *appletInterface = applet->property("_plasma_graphicObject").value()) { const auto &childItems = appletInterface->childItems(); if (childItems.isEmpty()) { continue; } KPluginMetaData meta = applet->kPackage().metadata(); for (QQuickItem *item : childItems) { if (auto *metaObject = item->metaObject()) { // not using QMetaObject::invokeMethod to avoid warnings when calling // this on applets that don't have it or other child items since this // is pretty much trial and error. // Also, "var" arguments are treated as QVariant in QMetaObject int methodIndex = modifier == static_cast(Qt::META) ? metaObject->indexOfMethod("activateTaskAtIndex(QVariant)") : metaObject->indexOfMethod("newInstanceForTaskAtIndex(QVariant)"); int methodIndex2 = metaObject->indexOfMethod("setShowTaskShortcutBadges(QVariant)"); if (methodIndex == -1 || (methodIndex2 == -1 && meta.pluginId() == "org.kde.latte.plasmoid")) { continue; } int showMethodIndex = -1; if (!m_viewItemsCalled.contains(item)) { m_viewItemsCalled.append(item); m_showShortcutBadgesMethods.append(metaObject->method(methodIndex)); showMethodIndex = m_showShortcutBadgesMethods.count() - 1; } else { showMethodIndex = m_showShortcutBadgesMethods.indexOf(metaObject->method(methodIndex)); } QMetaMethod method = metaObject->method(methodIndex); if (method.invoke(item, Q_ARG(QVariant, index - 1))) { if (methodIndex2 != -1) { m_showShortcutBadgesMethods[showMethodIndex].invoke(item, Q_ARG(QVariant, true)); } return true; } } } } } } return false; } bool GlobalShortcuts::activateLatteEntryAtContainment(const Latte::View *view, int index, Qt::Key modifier) { if (QQuickItem *containmentInterface = view->containment()->property("_plasma_graphicObject").value()) { const auto &childItems = containmentInterface->childItems(); for (QQuickItem *item : childItems) { if (auto *metaObject = item->metaObject()) { // not using QMetaObject::invokeMethod to avoid warnings when calling // this on applets that don't have it or other child items since this // is pretty much trial and error. // Also, "var" arguments are treated as QVariant in QMetaObject int methodIndex = modifier == static_cast(Qt::META) ? metaObject->indexOfMethod("activateEntryAtIndex(QVariant)") : metaObject->indexOfMethod("newInstanceForEntryAtIndex(QVariant)"); int methodIndex2 = metaObject->indexOfMethod("setShowAppletShortcutBadges(QVariant,QVariant,QVariant,QVariant)"); if (methodIndex == -1 || (methodIndex2 == -1)) { continue; } - int appLauncher = m_corona->universalSettings()->metaForwardedToLatte() ? + int appLauncher = m_corona->universalSettings()->kwin_metaForwardedToLatte() ? applicationLauncherId(view->containment()) : -1; int showMethodIndex = -1; if (!m_viewItemsCalled.contains(item)) { m_viewItemsCalled.append(item); m_showShortcutBadgesMethods.append(metaObject->method(methodIndex2)); showMethodIndex = m_showShortcutBadgesMethods.count() - 1; } else { showMethodIndex = m_showShortcutBadgesMethods.indexOf(metaObject->method(methodIndex2)); } QMetaMethod method = metaObject->method(methodIndex); if (view->visibility()->isHidden()) { //! delay the execution in order to show first the view QTimer::singleShot(APPLETEXECUTIONDELAY, [this, item, method, index]() { method.invoke(item, Q_ARG(QVariant, index)); }); return true; } else { if (method.invoke(item, Q_ARG(QVariant, index))) { return true; } } } } } return false; } //! Activate task manager entry void GlobalShortcuts::activateEntry(int index, Qt::Key modifier) { m_lastInvokedAction = dynamic_cast(sender()); QList sortedViews; CentralLayout *currentLayout = m_corona->layoutsManager()->currentLayout(); if (currentLayout) { sortedViews = currentLayout->sortedLatteViews(); } for (const auto view : sortedViews) { if (view->layout()->preferredForShortcutsTouched() && !view->isPreferredForShortcuts()) { continue; } if ((!view->latteTasksArePresent() && view->tasksPresent() && activatePlasmaTaskManagerEntryAtContainment(view->containment(), index, modifier)) || activateLatteEntryAtContainment(view, index, modifier)) { if (!m_hideViews.contains(view)) { m_hideViews.append(view); } view->visibility()->setBlockHiding(true); m_hideViewsTimer.start(); return; } } } //! update badge for specific view item void GlobalShortcuts::updateViewItemBadge(QString identifier, QString value) { //qDebug() << "DBUS CALL ::: " << identifier << " - " << value; auto updateBadgeForTaskInContainment = [this](const Plasma::Containment * c, QString identifier, QString value) { const auto &applets = c->applets(); for (auto *applet : applets) { KPluginMetaData meta = applet->kPackage().metadata(); if (meta.pluginId() == "org.kde.latte.plasmoid") { if (QQuickItem *appletInterface = applet->property("_plasma_graphicObject").value()) { const auto &childItems = appletInterface->childItems(); if (childItems.isEmpty()) { continue; } for (QQuickItem *item : childItems) { if (auto *metaObject = item->metaObject()) { // not using QMetaObject::invokeMethod to avoid warnings when calling // this on applets that don't have it or other child items since this // is pretty much trial and error. // Also, "var" arguments are treated as QVariant in QMetaObject int methodIndex = metaObject->indexOfMethod("updateBadge(QVariant,QVariant)"); if (methodIndex == -1) { continue; } QMetaMethod method = metaObject->method(methodIndex); if (method.invoke(item, Q_ARG(QVariant, identifier), Q_ARG(QVariant, value))) { return true; } } } } } } return false; }; CentralLayout *currentLayout = m_corona->layoutsManager()->currentLayout(); QList views; if (currentLayout) { views = currentLayout->latteViews(); } // update badges in all Latte Tasks plasmoids for (const auto &view : views) { updateBadgeForTaskInContainment(view->containment(), identifier, value); } } bool GlobalShortcuts::isCapableToShowShortcutBadges(Latte::View *view) { if (!view->latteTasksArePresent() && view->tasksPresent()) { return false; } const Plasma::Containment *c = view->containment(); if (QQuickItem *containmentInterface = c->property("_plasma_graphicObject").value()) { const auto &childItems = containmentInterface->childItems(); for (QQuickItem *item : childItems) { if (auto *metaObject = item->metaObject()) { // not using QMetaObject::invokeMethod to avoid warnings when calling // this on applets that don't have it or other child items since this // is pretty much trial and error. // Also, "var" arguments are treated as QVariant in QMetaObject int methodIndex = metaObject->indexOfMethod("setShowAppletShortcutBadges(QVariant,QVariant,QVariant,QVariant)"); if (methodIndex == -1) { continue; } return true; } } } return false; } int GlobalShortcuts::applicationLauncherId(const Plasma::Containment *c) { const auto applets = c->applets(); for (auto applet : applets) { const auto provides = applet->kPackage().metadata().value(QStringLiteral("X-Plasma-Provides")); if (provides.contains(QLatin1String("org.kde.plasma.launchermenu"))) { return applet->id(); } } return -1; } void GlobalShortcuts::showViews() { m_lastInvokedAction = dynamic_cast(sender()); if (!m_lastInvokedAction) { // when holding Meta m_lastInvokedAction = m_singleMetaAction; } auto invokeShowShortcuts = [this](const Plasma::Containment * c, const bool showLatteShortcuts, const bool showMeta) { if (QQuickItem *containmentInterface = c->property("_plasma_graphicObject").value()) { const auto &childItems = containmentInterface->childItems(); for (QQuickItem *item : childItems) { if (auto *metaObject = item->metaObject()) { // not using QMetaObject::invokeMethod to avoid warnings when calling // this on applets that don't have it or other child items since this // is pretty much trial and error. // Also, "var" arguments are treated as QVariant in QMetaObject int methodIndex = metaObject->indexOfMethod("setShowAppletShortcutBadges(QVariant,QVariant,QVariant,QVariant)"); if (methodIndex == -1) { continue; } - int appLauncher = m_corona->universalSettings()->metaForwardedToLatte() && showMeta ? + int appLauncher = m_corona->universalSettings()->kwin_metaForwardedToLatte() && showMeta ? applicationLauncherId(c) : -1; int showMethodIndex = -1; if (!m_viewItemsCalled.contains(item)) { m_viewItemsCalled.append(item); m_showShortcutBadgesMethods.append(metaObject->method(methodIndex)); showMethodIndex = m_showShortcutBadgesMethods.count() - 1; } else { showMethodIndex = m_showShortcutBadgesMethods.indexOf(metaObject->method(methodIndex)); } if (m_showShortcutBadgesMethods[showMethodIndex].invoke(item, Q_ARG(QVariant, showLatteShortcuts), Q_ARG(QVariant, true), Q_ARG(QVariant, showMeta), Q_ARG(QVariant, appLauncher))) { return true; } } } } return false; }; auto invokeShowOnlyMeta = [this](const Plasma::Containment * c, const bool showLatteShortcuts) { if (QQuickItem *containmentInterface = c->property("_plasma_graphicObject").value()) { const auto &childItems = containmentInterface->childItems(); for (QQuickItem *item : childItems) { if (auto *metaObject = item->metaObject()) { // not using QMetaObject::invokeMethod to avoid warnings when calling // this on applets that don't have it or other child items since this // is pretty much trial and error. // Also, "var" arguments are treated as QVariant in QMetaObject int methodIndex = metaObject->indexOfMethod("setShowAppletShortcutBadges(QVariant,QVariant,QVariant,QVariant)"); if (methodIndex == -1) { continue; } - int appLauncher = m_corona->universalSettings()->metaForwardedToLatte() ? + int appLauncher = m_corona->universalSettings()->kwin_metaForwardedToLatte() ? applicationLauncherId(c) : -1; int showMethodIndex = -1; if (!m_viewItemsCalled.contains(item)) { m_viewItemsCalled.append(item); m_showShortcutBadgesMethods.append(metaObject->method(methodIndex)); showMethodIndex = m_showShortcutBadgesMethods.count() - 1; } else { showMethodIndex = m_showShortcutBadgesMethods.indexOf(metaObject->method(methodIndex)); } if (m_showShortcutBadgesMethods[showMethodIndex].invoke(item, Q_ARG(QVariant, showLatteShortcuts), Q_ARG(QVariant, true), Q_ARG(QVariant, true), Q_ARG(QVariant, appLauncher))) { return true; } } } } return false; }; QList sortedViews; CentralLayout *currentLayout = m_corona->layoutsManager()->currentLayout(); if (currentLayout) { sortedViews = currentLayout->sortedLatteViews(); } Latte::View *viewWithTasks{nullptr}; Latte::View *viewWithMeta{nullptr}; for(const auto view : sortedViews) { if (!viewWithTasks && (!view->layout()->preferredForShortcutsTouched() || view->isPreferredForShortcuts()) && isCapableToShowShortcutBadges(view)) { viewWithTasks = view; break; } } //! show Meta if it is not already shown for Tasks Latte View if (!viewWithTasks || applicationLauncherId(viewWithTasks->containment()) == -1) { for(const auto view : sortedViews) { - if (!viewWithMeta && m_corona->universalSettings()->metaForwardedToLatte() && applicationLauncherId(view->containment()) > -1) { + if (!viewWithMeta && m_corona->universalSettings()->kwin_metaForwardedToLatte() && applicationLauncherId(view->containment()) > -1) { viewWithMeta = view; break; } } } bool viewFound{false}; if (!m_hideViewsTimer.isActive()) { m_hideViews.clear(); if (viewWithTasks || viewWithMeta) { m_viewItemsCalled.clear(); m_showShortcutBadgesMethods.clear(); } } //! show view that contains tasks plasmoid if (viewWithTasks && invokeShowShortcuts(viewWithTasks->containment(), true, true)) { viewFound = true; if (!m_hideViewsTimer.isActive()) { m_hideViews.append(viewWithTasks); viewWithTasks->visibility()->setBlockHiding(true); } } //! show view that contains only meta if (viewWithMeta && viewWithMeta != viewWithTasks && invokeShowOnlyMeta(viewWithMeta->containment(), false)) { viewFound = true; if (!m_hideViewsTimer.isActive()) { m_hideViews.append(viewWithMeta); viewWithMeta->visibility()->setBlockHiding(true); } } //! show all the rest views that contain plasma shortcuts QList viewsWithShortcuts; if (currentLayout) { viewsWithShortcuts = currentLayout->viewsWithPlasmaShortcuts(); } if (viewsWithShortcuts.count() > 0) { viewFound = true; if (!m_hideViewsTimer.isActive()) { for(const auto view : viewsWithShortcuts) { if (view != viewWithTasks && view != viewWithMeta) { if (invokeShowShortcuts(view->containment(), false, false)) { m_hideViews.append(view); view->visibility()->setBlockHiding(true); } } } } } if (viewFound) { if (!m_hideViewsTimer.isActive()) { m_hideViewsTimer.start(); } else { m_hideViewsTimer.stop(); hideViewsTimerSlot(); } } } bool GlobalShortcuts::viewsToHideAreValid() { for(const auto view : m_hideViews) { if (!m_corona->layoutsManager()->synchronizer()->latteViewExists(view)) { return false; } } return true; } void GlobalShortcuts::showSettings() { QList sortedViews; CentralLayout *currentLayout = m_corona->layoutsManager()->currentLayout(); if (currentLayout) { sortedViews = currentLayout->sortedLatteViews(); } //! find which is the next view to show its settings if (sortedViews.count() > 0) { int openSettings = -1; //! check if there is a view with opened settings window for (int i = 0; i < sortedViews.size(); ++i) { if (sortedViews[i] == currentLayout->lastConfigViewFor()) { openSettings = i; break; } } if (openSettings >= 0 && sortedViews.count() > 1) { openSettings = currentLayout->configViewIsShown() ? openSettings + 1 : openSettings; if (openSettings >= sortedViews.size()) { openSettings = 0; } sortedViews[openSettings]->showSettingsWindow(); } else { sortedViews[0]->showSettingsWindow(); } } } void GlobalShortcuts::hideViewsTimerSlot() { if (!m_lastInvokedAction || m_hideViews.count() == 0) { return; } auto initParameters = [this]() { m_lastInvokedAction = Q_NULLPTR; if (viewsToHideAreValid()) { for(const auto latteView : m_hideViews) { latteView->visibility()->setBlockHiding(false); } if (m_viewItemsCalled.count() > 0) { for (int i = 0; i < m_viewItemsCalled.count(); ++i) { m_showShortcutBadgesMethods[i].invoke(m_viewItemsCalled[i], Q_ARG(QVariant, false), Q_ARG(QVariant, false), Q_ARG(QVariant, false), Q_ARG(QVariant, -1)); } } } m_hideViews.clear(); m_viewItemsCalled.clear(); m_showShortcutBadgesMethods.clear(); m_metaShowedViews = false; }; // qDebug() << "MEMORY ::: " << m_hideViews.count() << " _ " << m_viewItemsCalled.count() << " _ " << m_showShortcutBadgesMethods.count(); if (QX11Info::isPlatformX11()) { if (!m_modifierTracker->sequenceModifierPressed(m_lastInvokedAction->shortcut())) { initParameters(); return; } else { m_hideViewsTimer.start(); } } else { // TODO: This is needs to be fixed in wayland initParameters(); } } } #include "moc_globalshortcuts.cpp"