diff --git a/app/shortcuts/globalshortcuts.cpp b/app/shortcuts/globalshortcuts.cpp index 6519c31b..eb127425 100644 --- a/app/shortcuts/globalshortcuts.cpp +++ b/app/shortcuts/globalshortcuts.cpp @@ -1,880 +1,886 @@ /* * 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 "../layoutmanager.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 View")); 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("Show Latte View Settings")); 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 layout settings")); layoutsAction->setText(i18n("Show Layout 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->layoutManager()->showLatteSettingsDialog(Types::LayoutPage); }); //show the latter universal settings QAction *universalSettingsAction = generalActions->addAction(QStringLiteral("show latte universal settings")); universalSettingsAction->setText(i18n("Show Latte Settings")); universalSettingsAction->setShortcut(QKeySequence(Qt::META + Qt::Key_E)); KGlobalAccel::setGlobalShortcut(universalSettingsAction, QKeySequence(Qt::META + Qt::Key_E)); connect(universalSettingsAction, &QAction::triggered, this, [this]() { m_modifierTracker->cancelMetaPressed(); m_corona->layoutManager()->showLatteSettingsDialog(Types::PreferencesPage); }); 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)); //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 = sortedViewsList(m_corona->layoutManager()->currentLatteViews()); foreach (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) { - m_modifierTracker->cancelMetaPressed(); - 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() ? 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_modifierTracker->cancelMetaPressed(); - m_lastInvokedAction = dynamic_cast(sender()); QList sortedViews = sortedViewsList(m_corona->layoutManager()->currentLatteViews()); - foreach (auto view, sortedViews) { - if ((!view->latteTasksPresent() && view->tasksPresent() && - activatePlasmaTaskManagerEntryAtContainment(view->containment(), index, modifier)) - || (view->isPreferredForShortcuts() && activateLatteEntryAtContainment(view, index, modifier))) { + if (m_shortcutsTracker->basedOnPositionEnabled()){ + foreach (auto view, sortedViews) { + if ((!view->latteTasksPresent() && view->tasksPresent() && + activatePlasmaTaskManagerEntryAtContainment(view->containment(), index, modifier)) + || activateLatteEntryAtContainment(view, index, modifier)) { - if (!m_hideViews.contains(view)) { - m_hideViews.append(view); - } + if (!m_hideViews.contains(view)) { + m_hideViews.append(view); + } - view->visibility()->setBlockHiding(true); - m_hideViewsTimer.start(); - return; + 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; }; QHash *views = m_corona->layoutManager()->currentLatteViews(); // update badges in all Latte Tasks plasmoids for (auto it = views->constBegin(), end = views->constEnd(); it != end; ++it) { updateBadgeForTaskInContainment(it.key(), identifier, value); } } bool GlobalShortcuts::isCapableToShowShortcutBadges(Latte::View *view) { if (!view->latteTasksPresent() && 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 ? 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() ? 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 = sortedViewsList(m_corona->layoutManager()->currentLatteViews()); Latte::View *viewWithTasks{nullptr}; Latte::View *viewWithMeta{nullptr}; - foreach (auto view, sortedViews) { - if (!viewWithTasks && view->isPreferredForShortcuts() && isCapableToShowShortcutBadges(view)) { - viewWithTasks = view; + if (m_shortcutsTracker->basedOnPositionEnabled()) { + foreach (auto view, sortedViews) { + if (!viewWithTasks && isCapableToShowShortcutBadges(view)) { + viewWithTasks = view; + break; + } } } //! show Meta if it is not already shown for Tasks Latte View if (!viewWithTasks || applicationLauncherId(viewWithTasks->containment()) == -1) { foreach (auto view, sortedViews) { if (!viewWithMeta && m_corona->universalSettings()->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 = m_corona->layoutManager()->currentViewsWithPlasmaShortcuts(); if (viewsWithShortcuts.count() > 0) { viewFound = true; if (!m_hideViewsTimer.isActive()) { foreach (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() { foreach (auto view, m_hideViews) { if (!m_corona->layoutManager()->latteViewExists(view)) { return false; } } return true; } bool GlobalShortcuts::viewAtLowerScreenPriority(Latte::View *test, Latte::View *base) { if (!base || ! test) { return true; } if (base->screen() == test->screen()) { return false; } else if (base->screen() != qGuiApp->primaryScreen() && test->screen() == qGuiApp->primaryScreen()) { return false; } else if (base->screen() == qGuiApp->primaryScreen() && test->screen() != qGuiApp->primaryScreen()) { return true; } else { int basePriority = -1; int testPriority = -1; for (int i = 0; i < qGuiApp->screens().count(); ++i) { if (base->screen() == qGuiApp->screens()[i]) { basePriority = i; } if (test->screen() == qGuiApp->screens()[i]) { testPriority = i; } } if (testPriority <= basePriority) { return true; } else { return false; } } qDebug() << "viewAtLowerScreenPriority : shouldn't had reached here..."; return false; } bool GlobalShortcuts::viewAtLowerEdgePriority(Latte::View *test, Latte::View *base) { if (!base || ! test) { return true; } QList edges{Plasma::Types::RightEdge, Plasma::Types::TopEdge, Plasma::Types::LeftEdge, Plasma::Types::BottomEdge}; int testPriority = -1; int basePriority = -1; for (int i = 0; i < edges.count(); ++i) { if (edges[i] == base->location()) { basePriority = i; } if (edges[i] == test->location()) { testPriority = i; } } if (testPriority < basePriority) return true; else return false; } QList GlobalShortcuts::sortedViewsList(QHash *views) { QList sortedViews; //! create views list to be sorted out for (auto it = views->constBegin(), end = views->constEnd(); it != end; ++it) { sortedViews.append(it.value()); } qDebug() << " -------- "; for (int i = 0; i < sortedViews.count(); ++i) { qDebug() << i << ". " << sortedViews[i]->screen()->name() << " - " << sortedViews[i]->location(); } //! sort the views based on screens and edges priorities //! views on primary screen have higher priority and //! for views in the same screen the priority goes to //! Bottom,Left,Top,Right for (int i = 0; i < sortedViews.size(); ++i) { for (int j = 0; j < sortedViews.size() - i - 1; ++j) { if (viewAtLowerScreenPriority(sortedViews[j], sortedViews[j + 1]) || (sortedViews[j]->screen() == sortedViews[j + 1]->screen() && viewAtLowerEdgePriority(sortedViews[j], sortedViews[j + 1]))) { Latte::View *temp = sortedViews[j + 1]; sortedViews[j + 1] = sortedViews[j]; sortedViews[j] = temp; } } } Latte::View *highestPriorityView{nullptr}; for (int i = 0; i < sortedViews.size(); ++i) { if (sortedViews[i]->isPreferredForShortcuts()) { highestPriorityView = sortedViews[i]; sortedViews.removeAt(i); break; } } if (highestPriorityView) { sortedViews.prepend(highestPriorityView); } qDebug() << " -------- sorted -----"; for (int i = 0; i < sortedViews.count(); ++i) { qDebug() << i << ". " << sortedViews[i]->isPreferredForShortcuts() << " - " << sortedViews[i]->screen()->name() << " - " << sortedViews[i]->location(); } return sortedViews; } void GlobalShortcuts::showSettings() { QList views = sortedViewsList(m_corona->layoutManager()->currentLatteViews()); //! find which is the next view to show its settings if (views.count() > 0) { int openSettings = -1; //! check if there is a view with opened settings window for (int i = 0; i < views.size(); ++i) { if (views[i]->settingsWindowIsShown()) { openSettings = i; break; } } if (openSettings >= 0 && views.count() > 1) { openSettings = openSettings + 1; if (openSettings >= views.size()) { openSettings = 0; } views[openSettings]->showSettingsWindow(); } else { views[0]->showSettingsWindow(); } } } void GlobalShortcuts::hideViewsTimerSlot() { if (!m_lastInvokedAction || m_hideViews.count() == 0) { return; } auto initParameters = [this]() { m_lastInvokedAction = Q_NULLPTR; if (viewsToHideAreValid()) { foreach (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" diff --git a/app/shortcuts/shortcutstracker.cpp b/app/shortcuts/shortcutstracker.cpp index 74481ca2..75445b80 100644 --- a/app/shortcuts/shortcutstracker.cpp +++ b/app/shortcuts/shortcutstracker.cpp @@ -1,184 +1,196 @@ /* * Copyright 2019 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 . */ // local #include "shortcutstracker.h" // Qt #include #include #include // KDE #include #include #include #define GLOBALSHORTCUTSCONFIG "kglobalshortcutsrc" #define APPLETSHORTCUTKEY "activate widget " namespace Latte { namespace ShortcutsPart { ShortcutsTracker::ShortcutsTracker(QObject *parent) : QObject(parent) { //! load global shortcuts badges at startup initGlobalShortcutsWatcher(); parseGlobalShortcuts(); clearAllAppletShortcuts(); } ShortcutsTracker::~ShortcutsTracker() { } void ShortcutsTracker::initGlobalShortcutsWatcher() { + for (int i=1; i<=19; ++i) { + m_badgesForActivate << QString(); + } + const QString globalShortcutsFilePath = QDir::homePath() + "/.config/" + GLOBALSHORTCUTSCONFIG; m_shortcutsConfigPtr = KSharedConfig::openConfig(globalShortcutsFilePath); KDirWatch::self()->addFile(globalShortcutsFilePath); connect(KDirWatch::self(), &KDirWatch::dirty, this, &ShortcutsTracker::shortcutsFileChanged, Qt::QueuedConnection); connect(KDirWatch::self(), &KDirWatch::created, this, &ShortcutsTracker::shortcutsFileChanged, Qt::QueuedConnection); } +bool ShortcutsTracker::basedOnPositionEnabled() const +{ + return m_basedOnPositionEnabled; +} + QStringList ShortcutsTracker::badgesForActivate() const { return m_badgesForActivate; } void ShortcutsTracker::shortcutsFileChanged(const QString &file) { if (!file.endsWith(GLOBALSHORTCUTSCONFIG)) { return; } m_shortcutsConfigPtr->reparseConfiguration(); parseGlobalShortcuts(); } QList ShortcutsTracker::appletsWithPlasmaShortcuts() { return m_appletShortcuts.keys(); } QString ShortcutsTracker::appletShortcutBadge(int appletId) { if (m_appletShortcuts.contains(appletId)) { return m_appletShortcuts[appletId]; } return QString(); } QString ShortcutsTracker::shortcutToBadge(QStringList shortcutRecords) { QString badge; if (shortcutRecords.count()>0 && shortcutRecords[0] != "none") { QStringList modifiers = shortcutRecords[0].split("+"); if (modifiers.count() >= 1) { badge = modifiers[modifiers.count() - 1]; //! when shortcut follows Meta+"Character" scheme if (modifiers.count() == 2 && modifiers[0] == "Meta") { badge = badge.toLower(); } else { badge = badge.toUpper(); } } } return badge; } void ShortcutsTracker::parseGlobalShortcuts() { KConfigGroup latteGroup = KConfigGroup(m_shortcutsConfigPtr, "lattedock"); //! make sure that latte dock records in global shortcuts where found correctly bool recordExists{true}; if (!latteGroup.exists()) { recordExists = false; } if (recordExists) { for (int i = 1; i <= 19; ++i) { QString entry = "activate entry " + QString::number(i); if (!latteGroup.hasKey(entry)) { recordExists = false; break; } } } if (recordExists) { m_badgesForActivate.clear(); m_appletShortcuts.clear(); for (int i = 1; i <= 19; ++i) { QString entry = "activate entry " + QString::number(i); QStringList records = latteGroup.readEntry(entry, QStringList()); m_badgesForActivate << shortcutToBadge(records); } + m_basedOnPositionEnabled = (!m_badgesForActivate[0].isEmpty() && !m_badgesForActivate[1].isEmpty()); + foreach(auto key, latteGroup.keyList()) { if (key.startsWith(APPLETSHORTCUTKEY)) { QStringList records = latteGroup.readEntry(key, QStringList()); int appletId = key.remove(APPLETSHORTCUTKEY).toInt(); m_appletShortcuts[appletId] = shortcutToBadge(records); } } - emit badgesForActivateChanged(); qDebug() << "badges updated to :: " << m_badgesForActivate; qDebug() << "applet shortcuts updated to :: " << m_appletShortcuts; + + emit badgesForActivateChanged(); } } void ShortcutsTracker::clearAllAppletShortcuts() { KConfigGroup latteGroup = KConfigGroup(m_shortcutsConfigPtr, "lattedock"); foreach(auto key, latteGroup.keyList()) { if (key.startsWith(APPLETSHORTCUTKEY)) { QAction *appletAction = new QAction(this); appletAction->setText(QString("Activate ") + key); appletAction->setObjectName(key); appletAction->setShortcut(QKeySequence()); KGlobalAccel::setGlobalShortcut(appletAction, QKeySequence()); KGlobalAccel::self()->removeAllShortcuts(appletAction); appletAction->deleteLater(); } } } } } diff --git a/app/shortcuts/shortcutstracker.h b/app/shortcuts/shortcutstracker.h index ceafddd6..78c0b3aa 100644 --- a/app/shortcuts/shortcutstracker.h +++ b/app/shortcuts/shortcutstracker.h @@ -1,75 +1,80 @@ /* * Copyright 2019 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 SHORTCUTSTRACKER_H #define SHORTCUTSTRACKER_H // Qt #include // KDE #include namespace Latte { namespace ShortcutsPart { class ShortcutsTracker: public QObject { Q_OBJECT + Q_PROPERTY(bool basedOnPositionEnabled READ basedOnPositionEnabled NOTIFY badgesForActivateChanged) Q_PROPERTY(QStringList badgesForActivate READ badgesForActivate NOTIFY badgesForActivateChanged) public: ShortcutsTracker(QObject *parent); ~ShortcutsTracker() override; void clearAllAppletShortcuts(); + bool basedOnPositionEnabled() const; + QStringList badgesForActivate() const; QList appletsWithPlasmaShortcuts(); public slots: Q_INVOKABLE QString appletShortcutBadge(int appletId); signals: void badgesForActivateChanged(); private slots: void shortcutsFileChanged(const QString &file); private: void initGlobalShortcutsWatcher(); //! access user set global shortcuts for activate entries void parseGlobalShortcuts(); QString shortcutToBadge(QStringList shortcutRecords); private: - QStringList m_badgesForActivate{"1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "z", "x", "c", "v", "b", "n", "m", ",", "."}; + bool m_basedOnPositionEnabled{false}; + + QStringList m_badgesForActivate; //! shortcuts assigned to applets through plasma infrastructure //! QHash m_appletShortcuts; KSharedConfig::Ptr m_shortcutsConfigPtr; }; } } #endif diff --git a/app/view/settings/primaryconfigview.cpp b/app/view/settings/primaryconfigview.cpp index 55785a89..1304b1ff 100644 --- a/app/view/settings/primaryconfigview.cpp +++ b/app/view/settings/primaryconfigview.cpp @@ -1,649 +1,652 @@ /* * 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 "primaryconfigview.h" // local #include "secondaryconfigview.h" #include "../panelshadows_p.h" #include "../view.h" #include "../../lattecorona.h" #include "../../layoutmanager.h" #include "../../settings/universalsettings.h" +#include "../../shortcuts/globalshortcuts.h" +#include "../../shortcuts/shortcutstracker.h" #include "../../wm/abstractwindowinterface.h" // Qt #include #include #include #include #include // KDE #include #include #include #include #include // Plasma #include namespace Latte { namespace ViewPart { PrimaryConfigView::PrimaryConfigView(Plasma::Containment *containment, Latte::View *view, QWindow *parent) : PlasmaQuick::ConfigView(containment, parent), m_latteView(view) { m_corona = qobject_cast(m_latteView->containment()->corona()); setupWaylandIntegration(); setScreen(m_latteView->screen()); if (containment) { setIcon(qGuiApp->windowIcon()); } m_screenSyncTimer.setSingleShot(true); m_screenSyncTimer.setInterval(100); connect(this, &PrimaryConfigView::complexityChanged, this, &PrimaryConfigView::saveConfig); connect(this, &PrimaryConfigView::complexityChanged, this, &PrimaryConfigView::updateShowInlineProperties); connect(this, &PrimaryConfigView::complexityChanged, this, &PrimaryConfigView::syncGeometry); connections << connect(&m_screenSyncTimer, &QTimer::timeout, this, [this]() { setScreen(m_latteView->screen()); setFlags(wFlags()); syncGeometry(); syncSlideEffect(); }); connections << connect(m_latteView->visibility(), &VisibilityManager::modeChanged, this, &PrimaryConfigView::syncGeometry); connections << connect(containment, &Plasma::Containment::immutabilityChanged, this, &PrimaryConfigView::immutabilityChanged); m_thicknessSyncTimer.setSingleShot(true); m_thicknessSyncTimer.setInterval(200); connections << connect(&m_thicknessSyncTimer, &QTimer::timeout, this, [this]() { syncGeometry(); }); connections << connect(m_latteView, &Latte::View::normalThicknessChanged, [&]() { m_thicknessSyncTimer.start(); }); if (m_corona) { connections << connect(m_corona, &Latte::Corona::raiseViewsTemporaryChanged, this, &PrimaryConfigView::raiseDocksTemporaryChanged); } } PrimaryConfigView::~PrimaryConfigView() { qDebug() << "ConfigView deleting ..."; deleteSecondaryWindow(); foreach (auto var, connections) { QObject::disconnect(var); } if (m_shellSurface) { delete m_shellSurface; m_shellSurface = nullptr; } } void PrimaryConfigView::init() { qDebug() << "dock config view : initialization started..."; m_originalByPassWM = m_latteView->byPassWM(); m_originalMode = m_latteView->visibility()->mode(); loadConfig(); setDefaultAlphaBuffer(true); setColor(Qt::transparent); PanelShadows::self()->addWindow(this); rootContext()->setContextProperty(QStringLiteral("latteView"), m_latteView); + rootContext()->setContextProperty(QStringLiteral("shortcutsEngine"), m_corona->globalShortcuts()->shortcutsTracker()); rootContext()->setContextProperty(QStringLiteral("viewConfig"), this); if (m_corona) { rootContext()->setContextProperty(QStringLiteral("universalSettings"), m_corona->universalSettings()); rootContext()->setContextProperty(QStringLiteral("layoutManager"), m_corona->layoutManager()); } KDeclarative::KDeclarative kdeclarative; kdeclarative.setDeclarativeEngine(engine()); kdeclarative.setTranslationDomain(QStringLiteral("latte-dock")); kdeclarative.setupBindings(); QByteArray tempFilePath = "lattedockconfigurationui"; updateEnabledBorders(); auto source = QUrl::fromLocalFile(m_latteView->containment()->corona()->kPackage().filePath(tempFilePath)); setSource(source); syncGeometry(); syncSlideEffect(); qDebug() << "dock config view : initialization ended..."; } inline Qt::WindowFlags PrimaryConfigView::wFlags() const { return (flags() | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint) & ~Qt::WindowDoesNotAcceptFocus; } QWindow *PrimaryConfigView::secondaryWindow() { return m_secConfigView; } void PrimaryConfigView::createSecondaryWindow() { if (m_secConfigView) { return; } m_secConfigView = new SecondaryConfigView(m_latteView, this); m_secConfigView->init(); } void PrimaryConfigView::deleteSecondaryWindow() { if (m_secConfigView) { m_secConfigView->deleteLater(); } } QRect PrimaryConfigView::geometryWhenVisible() const { return m_geometryWhenVisible; } void PrimaryConfigView::syncGeometry() { if (!m_latteView || !m_latteView->managedLayout() || !m_latteView->containment() || !rootObject()) { return; } const QSize size(rootObject()->width(), rootObject()->height()); setMaximumSize(size); setMinimumSize(size); resize(size); const auto location = m_latteView->containment()->location(); const auto sGeometry = m_latteView->screenGeometry(); int clearThickness = m_latteView->normalThickness() + m_latteView->fontPixelSize(); QPoint position{0, 0}; int xPos{0}; int yPos{0}; switch (m_latteView->formFactor()) { case Plasma::Types::Horizontal: { xPos = (m_complexity == Latte::Types::ExpertSettings) ? m_latteView->x() + m_latteView->width() - size.width() : sGeometry.center().x() - size.width() / 2; if (location == Plasma::Types::TopEdge) { yPos = sGeometry.y() + clearThickness; } else if (location == Plasma::Types::BottomEdge) { yPos = sGeometry.y() + sGeometry.height() - clearThickness - size.height(); } } break; case Plasma::Types::Vertical: { if (location == Plasma::Types::LeftEdge) { xPos = sGeometry.x() + clearThickness; yPos = m_latteView->geometry().center().y() - size.height() / 2; } else if (location == Plasma::Types::RightEdge) { xPos = sGeometry.x() + sGeometry.width() - clearThickness - size.width(); yPos = m_latteView->geometry().center().y() - size.height() / 2; } } break; default: qWarning() << "no sync geometry, wrong formFactor"; break; } position = {xPos, yPos}; updateEnabledBorders(); m_geometryWhenVisible = QRect(position.x(), position.y(), size.width(), size.height()); setPosition(position); if (m_shellSurface) { m_shellSurface->setPosition(position); } updateShowInlineProperties(); } void PrimaryConfigView::syncSlideEffect() { if (!m_latteView || !m_latteView->containment()) { return; } auto slideLocation = WindowSystem::Slide::None; switch (m_latteView->containment()->location()) { case Plasma::Types::TopEdge: slideLocation = WindowSystem::Slide::Top; break; case Plasma::Types::RightEdge: slideLocation = WindowSystem::Slide::Right; break; case Plasma::Types::BottomEdge: slideLocation = WindowSystem::Slide::Bottom; break; case Plasma::Types::LeftEdge: slideLocation = WindowSystem::Slide::Left; break; default: qDebug() << staticMetaObject.className() << "wrong location"; break; } m_corona->wm()->slideWindow(*this, slideLocation); } void PrimaryConfigView::showEvent(QShowEvent *ev) { QQuickWindow::showEvent(ev); if (!m_latteView) { return; } m_corona->wm()->setViewExtraFlags(*this); setFlags(wFlags()); m_corona->wm()->enableBlurBehind(*this); syncGeometry(); syncSlideEffect(); if (m_latteView && m_latteView->containment()) m_latteView->containment()->setUserConfiguring(true); m_screenSyncTimer.start(); QTimer::singleShot(400, this, &PrimaryConfigView::syncGeometry); emit showSignal(); } void PrimaryConfigView::hideEvent(QHideEvent *ev) { if (!m_latteView) { QQuickWindow::hideEvent(ev); return; } if (m_latteView->containment()) m_latteView->containment()->setUserConfiguring(false); QQuickWindow::hideEvent(ev); const auto mode = m_latteView->visibility()->mode(); if ((mode == Types::AlwaysVisible || mode == Types::WindowsGoBelow) && !(m_originalMode == Types::AlwaysVisible || m_originalMode == Types::WindowsGoBelow)) { //! mode changed to AlwaysVisible OR WindowsGoBelow FROM Dodge mode if (m_originalByPassWM) { //! if original by pass is active m_latteView->managedLayout()->recreateView(m_latteView->containment()); } } else if (m_latteView->byPassWM() != m_originalByPassWM) { m_latteView->managedLayout()->recreateView(m_latteView->containment()); } deleteLater(); } void PrimaryConfigView::focusOutEvent(QFocusEvent *ev) { Q_UNUSED(ev); const auto *focusWindow = qGuiApp->focusWindow(); if ((focusWindow && (focusWindow->flags().testFlag(Qt::Popup) || focusWindow->flags().testFlag(Qt::ToolTip))) || m_latteView->alternativesIsShown()) { return; } if (!m_blockFocusLost && (!m_secConfigView || (m_secConfigView && !m_secConfigView->isActive()))) { hideConfigWindow(); } } void PrimaryConfigView::setupWaylandIntegration() { if (m_shellSurface || !KWindowSystem::isPlatformWayland() || !m_latteView || !m_latteView->containment()) { // already setup return; } if (m_corona) { using namespace KWayland::Client; PlasmaShell *interface = m_corona->waylandCoronaInterface(); if (!interface) { return; } Surface *s = Surface::fromWindow(this); if (!s) { return; } qDebug() << "wayland dock window surface was created..."; m_shellSurface = interface->createSurface(s, this); m_shellSurface->setSkipTaskbar(true); syncGeometry(); } } bool PrimaryConfigView::event(QEvent *e) { if (e->type() == QEvent::PlatformSurface) { if (auto pe = dynamic_cast(e)) { switch (pe->surfaceEventType()) { case QPlatformSurfaceEvent::SurfaceCreated: if (m_shellSurface) { break; } setupWaylandIntegration(); break; case QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed: if (m_shellSurface) { delete m_shellSurface; m_shellSurface = nullptr; qDebug() << "WAYLAND config window surface was deleted..."; PanelShadows::self()->removeWindow(this); } break; } } } return PlasmaQuick::ConfigView::event(e); } void PrimaryConfigView::immutabilityChanged(Plasma::Types::ImmutabilityType type) { if (type != Plasma::Types::Mutable && isVisible()) hideConfigWindow(); } bool PrimaryConfigView::sticker() const { return m_blockFocusLost; } void PrimaryConfigView::setSticker(bool blockFocusLost) { if (m_blockFocusLost == blockFocusLost) return; m_blockFocusLost = blockFocusLost; } bool PrimaryConfigView::showInlineProperties() const { return m_showInlineProperties; } void PrimaryConfigView::setShowInlineProperties(bool show) { if (m_showInlineProperties == show) { return; } m_showInlineProperties = show; emit showInlinePropertiesChanged(); } void PrimaryConfigView::updateShowInlineProperties() { if (!m_latteView) { return; } bool showSecWindow{false}; bool complexityApprovedSecWindow{false}; if (m_complexity != Latte::Types::BasicSettings && !(m_complexity == Latte::Types::ExpertSettings && m_latteView->formFactor() == Plasma::Types::Vertical)) { showSecWindow = true; complexityApprovedSecWindow = true; } //! consider screen geometry for showing or not the secondary window if (!geometryWhenVisible().isNull()) { createSecondaryWindow(); if (m_secConfigView->geometryWhenVisible().intersects(geometryWhenVisible())) { showSecWindow = false; } else if (complexityApprovedSecWindow) { showSecWindow = true; } } if (showSecWindow) { if (!m_secConfigView) { createSecondaryWindow(); } if (!KWindowSystem::isPlatformWayland()) { QTimer::singleShot(150, m_secConfigView, SLOT(show())); } else { QTimer::singleShot(150, [this]() { m_secConfigView->setVisible(true); }); } setShowInlineProperties(false); } else { deleteSecondaryWindow(); setShowInlineProperties(true); } // qDebug() << " showSecWindow:" << showSecWindow << " _ " << " inline:"<< !showSecWindow; } int PrimaryConfigView::complexity() const { return (int)m_complexity; } void PrimaryConfigView::setComplexity(int complexity) { if ((int)m_complexity == complexity) { return; } m_complexity = static_cast(complexity); emit complexityChanged(); } void PrimaryConfigView::hideConfigWindow() { if (m_shellSurface) { //!NOTE: Avoid crash in wayland environment with qt5.9 close(); } else { hide(); } } void PrimaryConfigView::updateLaunchersForGroup(int groupInt) { Types::LaunchersGroup group = (Types::LaunchersGroup)groupInt; //! when the layout/global launchers list is empty then the current dock launchers are used for them //! as a start point if (m_corona && m_latteView->managedLayout()) { if ((group == Types::LayoutLaunchers && m_latteView->managedLayout()->launchers().isEmpty()) || (group == Types::GlobalLaunchers && m_corona->universalSettings()->launchers().isEmpty())) { Plasma::Containment *c = m_latteView->containment(); 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("getLauncherList()"); if (methodIndex == -1) { continue; } QMetaMethod method = metaObject->method(methodIndex); QVariant launchers; if (method.invoke(item, Q_RETURN_ARG(QVariant, launchers))) { if (group == Types::LayoutLaunchers) { m_latteView->managedLayout()->setLaunchers(launchers.toStringList()); } else if (group == Types::GlobalLaunchers) { m_corona->universalSettings()->setLaunchers(launchers.toStringList()); } } } } } } } } } } //!BEGIN borders Plasma::FrameSvg::EnabledBorders PrimaryConfigView::enabledBorders() const { return m_enabledBorders; } void PrimaryConfigView::updateEnabledBorders() { if (!this->screen()) { return; } Plasma::FrameSvg::EnabledBorders borders = Plasma::FrameSvg::AllBorders; switch (m_latteView->location()) { case Plasma::Types::TopEdge: borders &= m_inReverse ? ~Plasma::FrameSvg::BottomBorder : ~Plasma::FrameSvg::TopBorder; break; case Plasma::Types::LeftEdge: borders &= ~Plasma::FrameSvg::LeftBorder; break; case Plasma::Types::RightEdge: borders &= ~Plasma::FrameSvg::RightBorder; break; case Plasma::Types::BottomEdge: borders &= m_inReverse ? ~Plasma::FrameSvg::TopBorder : ~Plasma::FrameSvg::BottomBorder; break; default: break; } if (m_enabledBorders != borders) { m_enabledBorders = borders; PanelShadows::self()->addWindow(this, m_enabledBorders); emit enabledBordersChanged(); } } //!END borders //!BEGIN configuration void PrimaryConfigView::loadConfig() { if (!m_latteView || !m_latteView->containment()) { return; } auto config = m_latteView->containment()->config(); int complexity = config.readEntry("settingsComplexity", (int)Latte::Types::BasicSettings); setComplexity(static_cast(complexity)); } void PrimaryConfigView::saveConfig() { if (!m_latteView || !m_latteView->containment()) { return; } auto config = m_latteView->containment()->config(); config.writeEntry("settingsComplexity", (int)m_complexity); config.sync(); } //!END configuration } } diff --git a/containment/package/contents/config/main.xml b/containment/package/contents/config/main.xml index a482f1d8..6d754664 100644 --- a/containment/package/contents/config/main.xml +++ b/containment/package/contents/config/main.xml @@ -1,319 +1,319 @@ 0 10 64 15 true -1 true 0 true false 100 false true true true true false false false false -1 -1 2 0 70 30 080808 false 0 true 30 0 0 100 0 6 2 0 0 1 0 false 100 100 false false false 2 0 - + false false true false false true true true true - + true true true diff --git a/shell/package/contents/configuration/pages/BehaviorConfig.qml b/shell/package/contents/configuration/pages/BehaviorConfig.qml index e8dba857..9b123877 100644 --- a/shell/package/contents/configuration/pages/BehaviorConfig.qml +++ b/shell/package/contents/configuration/pages/BehaviorConfig.qml @@ -1,635 +1,636 @@ /* * 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 . */ import QtQuick 2.0 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.3 import QtGraphicalEffects 1.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.plasma.components 3.0 as PlasmaComponents3 import org.kde.plasma.plasmoid 2.0 import org.kde.latte 0.2 as Latte import "../../controls" as LatteExtraControls PlasmaComponents.Page { Layout.maximumWidth: content.width + content.Layout.leftMargin * 2 Layout.maximumHeight: content.height + units.smallSpacing * 2 property alias dockTypeSelection: _dockTypeSelection ColumnLayout { id: content width: (dialog.appliedWidth - units.smallSpacing * 2) - Layout.leftMargin * 2 spacing: dialog.subGroupSpacing anchors.horizontalCenter: parent.horizontalCenter Layout.leftMargin: units.smallSpacing * 2 //! BEGIN: Inline Dock/Panel Type, it is used only when the secondary window //! overlaps the main dock config window ColumnLayout { Layout.fillWidth: true spacing: units.smallSpacing Layout.topMargin: units.smallSpacing visible: dialog.highLevel && viewConfig.showInlineProperties LatteExtraControls.Header { text: i18n("Type") } LatteExtraControls.TypeSelection{ id: _dockTypeSelection horizontal: true } } //! END: Inline Dock/Panel Type //! BEGIN: Location ColumnLayout { Layout.fillWidth: true spacing: units.smallSpacing Layout.topMargin: units.smallSpacing LatteExtraControls.Header { text: i18n("Location") } RowLayout { id: screenRow Layout.fillWidth: true Layout.leftMargin: units.smallSpacing * 2 Layout.rightMargin: units.smallSpacing * 2 spacing: 2 visible: true function updateScreens() { if (universalSettings.screens.length > 1) screenRow.visible = true; else screenRow.visible = false; var screens = [] var rtlSpace = Qt.application.layoutDirection === Qt.RightToLeft ? " " : ""; screens.push(rtlSpace + i18n("On Primary")); //check if the screen exists, it is used in cases Latte is moving //the view automatically to primaryScreen in order for the user //to has always a view with tasks shown var screenExists = false for (var i = 0; i < universalSettings.screens.length; i++) { if (universalSettings.screens[i].name === latteView.positioner.currentScreenName) screenExists = true; } if (!screenExists && !latteView.onPrimary) screens.push(rtlSpace + latteView.positioner.currentScreenName); for (var i = 0; i < universalSettings.screens.length; i++) { screens.push(rtlSpace + universalSettings.screens[i].name) } screenCmb.model = screens; if (latteView.onPrimary) { screenCmb.currentIndex = 0; } else { screenCmb.currentIndex = screenCmb.find(latteView.positioner.currentScreenName); } console.log(latteView.positioner.currentScreenName); } Connections{ target: viewConfig onShowSignal: screenRow.updateScreens(); } PlasmaComponents.Label { text: i18n("Screen:") Layout.alignment: Qt.AlignRight } PlasmaComponents3.ComboBox { id: screenCmb Layout.fillWidth: true Component.onCompleted: screenRow.updateScreens(); //they are used to restore the index when the screen edge //is occupied property bool acceptedIndex: true property int previousIndex: -1 onCurrentIndexChanged: { //it is used to restore the index when the screen edge //is occupied if (!acceptedIndex) { acceptedIndex = true; currentIndex = previousIndex; } } onActivated: { previousIndex = currentIndex; if (index === 0) { var succeed = latteView.positioner.setCurrentScreen("primary"); latteView.onPrimary = true; acceptedIndex = true; } else if (index>0 && (index !== find(latteView.positioner.currentScreenName) || latteView.onPrimary)) { console.log("current index changed!!! :"+ index); console.log("screen must be changed..."); var succeed = latteView.positioner.setCurrentScreen(textAt(index)); if(succeed) { latteView.onPrimary = false; } else { console.log("the edge is already occupied!!!"); acceptedIndex = false; } } } } } RowLayout { id: locationLayout Layout.fillWidth: true Layout.leftMargin: units.smallSpacing * 2 Layout.rightMargin: units.smallSpacing * 2 LayoutMirroring.enabled: false spacing: 2 Connections{ target: latteView onDockLocationChanged: locationLayout.lockReservedEdges(); } Connections{ target: latteView.managedLayout onViewsCountChanged: locationLayout.lockReservedEdges(); } Connections{ target: latteView.positioner onCurrentScreenChanged: locationLayout.lockReservedEdges(); } Component.onCompleted: lockReservedEdges() ExclusiveGroup { id: locationGroup property bool inStartup: true onCurrentChanged: { if (current.checked && !inStartup) { latteView.positioner.hideDockDuringLocationChange(current.edge); } inStartup = false; } } function lockReservedEdges() { var edges = latteView.managedLayout.qmlFreeEdges(latteView.positioner.currentScreenId); bottomEdgeBtn.edgeIsFree = (edges.indexOf(bottomEdgeBtn.edge)>=0); topEdgeBtn.edgeIsFree = (edges.indexOf(topEdgeBtn.edge)>=0); leftEdgeBtn.edgeIsFree = (edges.indexOf(leftEdgeBtn.edge)>=0); rightEdgeBtn.edgeIsFree = (edges.indexOf(rightEdgeBtn.edge)>=0); } PlasmaComponents.Button { id: bottomEdgeBtn Layout.fillWidth: true text: i18nc("bottom location", "Bottom") iconSource: "arrow-down" checked: latteView.location === edge checkable: true enabled: checked || edgeIsFree exclusiveGroup: locationGroup property bool edgeIsFree: true readonly property int edge: PlasmaCore.Types.BottomEdge } PlasmaComponents.Button { id: leftEdgeBtn Layout.fillWidth: true text: i18nc("left location", "Left") iconSource: "arrow-left" checked: latteView.location === edge checkable: true enabled: checked || edgeIsFree exclusiveGroup: locationGroup property bool edgeIsFree: true readonly property int edge: PlasmaCore.Types.LeftEdge } PlasmaComponents.Button { id: topEdgeBtn Layout.fillWidth: true text: i18nc("top location", "Top") iconSource: "arrow-up" checked: latteView.location === edge checkable: true enabled: checked || edgeIsFree exclusiveGroup: locationGroup property bool edgeIsFree: true readonly property int edge: PlasmaCore.Types.TopEdge } PlasmaComponents.Button { id: rightEdgeBtn Layout.fillWidth: true text: i18nc("right location", "Right") iconSource: "arrow-right" checked: latteView.location === edge checkable: true enabled: checked || edgeIsFree exclusiveGroup: locationGroup property bool edgeIsFree: true readonly property int edge: PlasmaCore.Types.RightEdge } } } //! END: Location //! BEGIN: Alignment ColumnLayout { Layout.fillWidth: true spacing: units.smallSpacing LatteExtraControls.Header { text: i18n("Alignment") } RowLayout { Layout.fillWidth: true Layout.leftMargin: units.smallSpacing * 2 Layout.rightMargin: units.smallSpacing * 2 LayoutMirroring.enabled: false spacing: 2 property int panelPosition: plasmoid.configuration.panelPosition onPanelPositionChanged: { if (panelPosition === Latte.Types.Justify) latteView.addInternalViewSplitter() else latteView.removeInternalViewSplitter() } Component.onCompleted: { if (panelPosition === Latte.Types.Justify) latteView.addInternalViewSplitter() else latteView.removeInternalViewSplitter() } ExclusiveGroup { id: alignmentGroup onCurrentChanged: { if (current.checked) plasmoid.configuration.panelPosition = current.position } } PlasmaComponents.Button { Layout.fillWidth: true text: panelIsVertical ? i18nc("top alignment", "Top") : i18nc("left alignment", "Left") iconSource: panelIsVertical ? "format-align-vertical-top" : "format-justify-left" checked: parent.panelPosition === position checkable: true exclusiveGroup: alignmentGroup property int position: panelIsVertical ? Latte.Types.Top : Latte.Types.Left } PlasmaComponents.Button { Layout.fillWidth: true text: i18nc("center alignment", "Center") iconSource: panelIsVertical ? "format-align-vertical-center" : "format-justify-center" checked: parent.panelPosition === position checkable: true exclusiveGroup: alignmentGroup property int position: Latte.Types.Center } PlasmaComponents.Button { Layout.fillWidth: true text: panelIsVertical ? i18nc("bottom alignment", "Bottom") : i18nc("right alignment", "Right") iconSource: panelIsVertical ? "format-align-vertical-bottom" : "format-justify-right" checked: parent.panelPosition === position checkable: true exclusiveGroup: alignmentGroup property int position: panelIsVertical ? Latte.Types.Bottom : Latte.Types.Right } PlasmaComponents.Button { Layout.fillWidth: true text: i18nc("justify alignment", "Justify") iconSource: "format-justify-fill" checked: parent.panelPosition === position checkable: true exclusiveGroup: alignmentGroup property int position: Latte.Types.Justify } } } //! END: Alignment //! BEGIN: Visibility ColumnLayout { Layout.fillWidth: true spacing: units.smallSpacing LatteExtraControls.Header { text: i18n("Visibility") } GridLayout { width: parent.width rowSpacing: 1 columnSpacing: 2 Layout.leftMargin: units.smallSpacing * 2 Layout.rightMargin: units.smallSpacing * 2 columns: 2 property int mode: latteView.visibility.mode ExclusiveGroup { id: visibilityGroup onCurrentChanged: { if (current.checked) latteView.visibility.mode = current.mode } } PlasmaComponents.Button { Layout.fillWidth: true text: i18n("Always Visible") checked: parent.mode === mode checkable: true exclusiveGroup: visibilityGroup property int mode: Latte.Types.AlwaysVisible } PlasmaComponents.Button { Layout.fillWidth: true text: i18n("Auto Hide") checked: parent.mode === mode checkable: true exclusiveGroup: visibilityGroup property int mode: Latte.Types.AutoHide } PlasmaComponents.Button { Layout.fillWidth: true text: i18n("Dodge Active") checked: parent.mode === mode checkable: true exclusiveGroup: visibilityGroup property int mode: Latte.Types.DodgeActive } PlasmaComponents.Button { Layout.fillWidth: true text: i18n("Dodge Maximized") checked: parent.mode === mode checkable: true exclusiveGroup: visibilityGroup property int mode: Latte.Types.DodgeMaximized } PlasmaComponents.Button { Layout.fillWidth: true text: i18n("Dodge All Windows") checked: parent.mode === mode checkable: true exclusiveGroup: visibilityGroup property int mode: Latte.Types.DodgeAllWindows } PlasmaComponents.Button { Layout.fillWidth: true text: i18n("Windows Go Below") checked: parent.mode === mode checkable: true exclusiveGroup: visibilityGroup property int mode: Latte.Types.WindowsGoBelow } } } //! END: Visibility //! BEGIN: Delay ColumnLayout { Layout.fillWidth: true spacing: units.smallSpacing enabled: !(latteView.visibility.mode === Latte.Types.AlwaysVisible || latteView.visibility.mode === Latte.Types.WindowsGoBelow) LatteExtraControls.Header { Layout.fillWidth: true text: i18n("Delay") } RowLayout { Layout.fillWidth: false Layout.leftMargin: units.smallSpacing * 2 Layout.rightMargin: units.smallSpacing * 2 Layout.alignment: Qt.AlignHCenter spacing: 2 PlasmaComponents.Label { Layout.fillWidth: false Layout.rightMargin: Qt.application.layoutDirection === Qt.RightToLeft ? 0 : units.smallSpacing Layout.leftMargin: Qt.application.layoutDirection === Qt.RightToLeft ? units.smallSpacing : 0 horizontalAlignment: Text.AlignRight text: i18n("Show") } LatteExtraControls.TextField { Layout.preferredWidth: width text: latteView.visibility.timerShow onValueChanged: { latteView.visibility.timerShow = value } } PlasmaComponents.Label { Layout.fillWidth: false Layout.leftMargin: Qt.application.layoutDirection === Qt.RightToLeft ? units.smallSpacing : units.largeSpacing Layout.rightMargin: Qt.application.layoutDirection === Qt.RightToLeft ? units.largeSpacing : units.smallSpacing horizontalAlignment: Text.AlignRight text: i18n("Hide") } LatteExtraControls.TextField{ Layout.preferredWidth: width text: latteView.visibility.timerHide onValueChanged: { latteView.visibility.timerHide = value } } } } //! END: Delay //! BEGIN: Items ColumnLayout { spacing: units.smallSpacing Layout.rightMargin: units.smallSpacing * 2 visible: dialog.expertLevel LatteExtraControls.Header { text: i18n("Items") } PlasmaComponents.CheckBox { id: titleTooltipsChk Layout.leftMargin: units.smallSpacing * 2 text: i18n("Show title tooltips on hovering") checked: plasmoid.configuration.titleTooltips onClicked: { plasmoid.configuration.titleTooltips = checked; } } PlasmaComponents.CheckBox { id: mouseWheelChk Layout.leftMargin: units.smallSpacing * 2 text: i18n("Activate through mouse wheel") checked: plasmoid.configuration.mouseWheelActions tooltip: i18n("Enable/Disable the mouse wheel action") visible: dialog.highLevel onClicked: { plasmoid.configuration.mouseWheelActions = checked } } - PlasmaComponents.CheckBox { - Layout.leftMargin: units.smallSpacing * 2 - text: i18n("Activate based on position through global shortcuts") - checked: latteView.isPreferredForShortcuts - - tooltip: i18n("This view activates its items based on their position through global shortcuts. Take note that only one view can have that option enabled for each layout") - - onClicked: { - latteView.isPreferredForShortcuts = checked - } - } - PlasmaComponents.CheckBox { Layout.leftMargin: units.smallSpacing * 2 text: i18n("Decrease size automatically when needed") checked: plasmoid.configuration.autoDecreaseIconSize tooltip: i18n("Items size is decreased automatically when the contents exceed the maximum length \n\nHint: this option is disabled when plasma taskmanagers are present") enabled: !(latteView.tasksPresent() && !latteView.latteTasksPresent()); onClicked: { plasmoid.configuration.autoDecreaseIconSize = checked } } } //! END: Items //! BEGIN: Adjust ColumnLayout { spacing: units.smallSpacing Layout.rightMargin: units.smallSpacing * 2 visible: dialog.expertLevel LatteExtraControls.Header { text: i18n("Environment") } PlasmaComponents.CheckBox { Layout.leftMargin: units.smallSpacing * 2 text: i18n("Activate KWin edge after hiding") checked: latteView.visibility.enableKWinEdges tooltip: i18n("After the view becomes hidden, KWin is informed to track user feedback. For example an edge visual hint is shown whenever the mouse approaches the hidden view") onClicked: { latteView.visibility.enableKWinEdges = checked; } } + PlasmaComponents.CheckBox { + Layout.leftMargin: units.smallSpacing * 2 + text: i18n("Prefer for based on position global shortcuts") + checked: latteView.isPreferredForShortcuts + enabled: shortcutsEngine.basedOnPositionEnabled + + tooltip: i18n("This view is preferred to use the based on position global shortcuts. Take note that only one view can have that option enabled for each layout") + + onClicked: { + latteView.isPreferredForShortcuts = checked + } + } + PlasmaComponents.CheckBox { Layout.leftMargin: units.smallSpacing * 2 text: i18n("Can be above fullscreen windows") checked: latteView.byPassWM enabled: !(latteView.visibility.mode === Latte.Types.AlwaysVisible || latteView.visibility.mode === Latte.Types.WindowsGoBelow) tooltip: i18n("BypassWindowManagerHint flag for the window. The view will be above all windows even those set as 'Always On Top'") onCheckedChanged: { latteView.byPassWM = checked; } } PlasmaComponents.CheckBox { Layout.leftMargin: units.smallSpacing * 2 text: i18n("Raise on desktop change") checked: latteView.visibility.raiseOnDesktop enabled: latteView.visibility.mode !== Latte.Types.AlwaysVisible onClicked: { latteView.visibility.raiseOnDesktop = checked } } PlasmaComponents.CheckBox { Layout.leftMargin: units.smallSpacing * 2 text: i18n("Raise on activity change") checked: latteView.visibility.raiseOnActivity enabled: latteView.visibility.mode !== Latte.Types.AlwaysVisible onClicked: { latteView.visibility.raiseOnActivity = checked } } } //! END: Adjust //! Bottom spacer PlasmaComponents.Label{ id: bottomMarginSpacer text:" " } } } diff --git a/shell/package/contents/configuration/pages/TasksConfig.qml b/shell/package/contents/configuration/pages/TasksConfig.qml index 890b1abc..5c9b329b 100644 --- a/shell/package/contents/configuration/pages/TasksConfig.qml +++ b/shell/package/contents/configuration/pages/TasksConfig.qml @@ -1,516 +1,516 @@ /* * 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 . */ import QtQuick 2.7 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.3 import QtGraphicalEffects 1.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.plasma.components 3.0 as PlasmaComponents3 import org.kde.plasma.plasmoid 2.0 import org.kde.latte 0.2 as Latte import "../../controls" as LatteExtraControls PlasmaComponents.Page { Layout.maximumWidth: content.width + content.Layout.leftMargin * 2 Layout.maximumHeight: content.height + units.smallSpacing * 2 property bool disableAllWindowsFunctionality: plasmoid.configuration.showWindowsOnlyFromLaunchers && plasmoid.configuration.activeIndicator === Latte.Types.NoneIndicator ColumnLayout { id: content width: (dialog.appliedWidth - units.smallSpacing * 2) - Layout.leftMargin * 2 spacing: dialog.subGroupSpacing anchors.horizontalCenter: parent.horizontalCenter Layout.leftMargin: units.smallSpacing * 2 Layout.rightMargin: units.smallSpacing * 2 //! BEGIN: Tasks Appearance ColumnLayout { spacing: units.smallSpacing Layout.topMargin: units.smallSpacing Layout.rightMargin: units.smallSpacing * 2 enabled: !disableAllWindowsFunctionality LatteExtraControls.Header { text: i18n("Appearance") } PlasmaComponents.CheckBox { id: threeColorsWindows Layout.leftMargin: units.smallSpacing * 2 text: i18n("Different color for minimized windows") checked: plasmoid.configuration.threeColorsWindows onClicked: { plasmoid.configuration.threeColorsWindows = checked } } PlasmaComponents.CheckBox { id: dotsOnActive Layout.leftMargin: units.smallSpacing * 2 text: i18n("Show an extra dot for grouped windows when active") checked: plasmoid.configuration.dotsOnActive tooltip: i18n("Grouped windows show both a line and a dot when \none of them is active and the Line Active Indicator \nis enabled") visible: dialog.highLevel enabled: plasmoid.configuration.activeIndicatorType === Latte.Types.LineIndicator onClicked: { plasmoid.configuration.dotsOnActive = checked } } } //! END: Tasks Appearance //! BEGIN: Badges ColumnLayout { spacing: units.smallSpacing Layout.topMargin: units.smallSpacing Layout.rightMargin: units.smallSpacing * 2 visible: dialog.highLevel LatteExtraControls.Header { text: i18n("Badges") } PlasmaComponents.CheckBox { Layout.leftMargin: units.smallSpacing * 2 text: i18n("Unread messages from tasks") checked: plasmoid.configuration.showInfoBadge tooltip: i18n("Show unread messages or information from tasks") onClicked: { plasmoid.configuration.showInfoBadge = checked } } PlasmaComponents.CheckBox { Layout.leftMargin: units.smallSpacing * 2 text: i18n("Progress information for tasks") checked: plasmoid.configuration.showProgressBadge tooltip: i18n("Show a progress animation for tasks e.g. when copying files with Dolphin") onClicked: { plasmoid.configuration.showProgressBadge = checked } } PlasmaComponents.CheckBox { Layout.leftMargin: units.smallSpacing * 2 text: i18n("Audio playing from tasks") checked: plasmoid.configuration.showAudioBadge tooltip: i18n("Show audio playing from tasks, the user is able to mute/unmute or change the volume") onClicked: { plasmoid.configuration.showAudioBadge = checked } } } //! END: Badges //! BEGIN: Tasks Interaction ColumnLayout { spacing: units.smallSpacing Layout.rightMargin: units.smallSpacing * 2 LatteExtraControls.Header { text: i18n("Interaction") } PlasmaComponents.CheckBox { Layout.leftMargin: units.smallSpacing * 2 text: i18n("Add launchers only in the Tasks Area") checked: plasmoid.configuration.addLaunchersInTaskManager tooltip: i18n("Launchers are added only in the taskmanager and not as plasma applets") onClicked: { plasmoid.configuration.addLaunchersInTaskManager = checked; } } PlasmaComponents.CheckBox { id: windowActionsChk Layout.leftMargin: units.smallSpacing * 2 text: i18n("Show window actions in the context menu") checked: plasmoid.configuration.showWindowActions visible: dialog.highLevel enabled: !disableAllWindowsFunctionality onClicked: { plasmoid.configuration.showWindowActions = checked } } PlasmaComponents.CheckBox { id: unifyGlobalShortcutsChk Layout.leftMargin: units.smallSpacing * 2 - text: i18n("Activate based on position shortcuts only for tasks") + text: i18n("Based on position shortcuts apply only for tasks") checked: !plasmoid.configuration.unifiedGlobalShortcuts - tooltip: i18n("Based on position global shortcuts are enabled for tasks but are disabled for applets") + tooltip: i18n("Based on position global shortcuts are enabled only for tasks and not for applets") visible: dialog.highLevel - enabled: latteView.isPreferredForShortcuts + enabled: shortcutsEngine.basedOnPositionEnabled onClicked: { plasmoid.configuration.unifiedGlobalShortcuts = !checked } } } //! END: Tasks Interaction //! BEGIN: Tasks Filters ColumnLayout { spacing: units.smallSpacing Layout.rightMargin: units.smallSpacing * 2 LatteExtraControls.Header { text: i18n("Filters") } PlasmaComponents.CheckBox { id: showOnlyCurrentScreen Layout.leftMargin: units.smallSpacing * 2 text: i18n("Show only tasks from the current screen") checked: plasmoid.configuration.showOnlyCurrentScreen onClicked: { plasmoid.configuration.showOnlyCurrentScreen = checked } } PlasmaComponents.CheckBox { id: showOnlyCurrentDesktop Layout.leftMargin: units.smallSpacing * 2 text: i18n("Show only tasks from the current desktop") checked: plasmoid.configuration.showOnlyCurrentDesktop onClicked: { plasmoid.configuration.showOnlyCurrentDesktop = checked } } PlasmaComponents.CheckBox { id: showOnlyCurrentActivity Layout.leftMargin: units.smallSpacing * 2 text: i18n("Show only tasks from the current activity") checked: plasmoid.configuration.showOnlyCurrentActivity onClicked: { plasmoid.configuration.showOnlyCurrentActivity = checked } } PlasmaComponents.CheckBox { id: showWindowsOnlyFromLaunchersChk Layout.leftMargin: units.smallSpacing * 2 text: i18n("Show only tasks from launchers") checked: plasmoid.configuration.showWindowsOnlyFromLaunchers visible: dialog.highLevel onClicked: { plasmoid.configuration.showWindowsOnlyFromLaunchers = checked } } PlasmaComponents.CheckBox { id: groupTasksChk Layout.leftMargin: units.smallSpacing * 2 text: i18n("Group tasks of the same application") checked: plasmoid.configuration.groupTasksByDefault tooltip: i18n("By default group tasks of the same application") visible: dialog.highLevel onClicked: { plasmoid.configuration.groupTasksByDefault = checked } } } //! END: Tasks Filters //! BEGIN: Launchers Group ColumnLayout { spacing: units.smallSpacing Layout.rightMargin: units.smallSpacing * 2 LatteExtraControls.Header { text: i18n("Launchers") } RowLayout { Layout.fillWidth: true Layout.leftMargin: units.smallSpacing * 2 spacing: 2 property int group: plasmoid.configuration.launchersGroup ExclusiveGroup { id: launchersGroup onCurrentChanged: { if (current.checked) { viewConfig.updateLaunchersForGroup(current.group); plasmoid.configuration.launchersGroup = current.group; } } } PlasmaComponents.Button { Layout.fillWidth: true text: i18nc("unique launchers group","Unique") checked: parent.group === group checkable: true exclusiveGroup: launchersGroup tooltip: i18n("Use a unique set of launchers for this view which is independent from any other view") readonly property int group: Latte.Types.UniqueLaunchers } PlasmaComponents.Button { Layout.fillWidth: true text: i18nc("layout launchers group","Layout") checked: parent.group === group checkable: true exclusiveGroup: launchersGroup tooltip: i18n("Use the current layout set of launchers for this latteView. This group provides launchers synchronization between different views in the same layout") //! it is shown only when the user has activated that option manually from the text layout file visible: plasmoid.configuration.launchersGroup === group readonly property int group: Latte.Types.LayoutLaunchers } PlasmaComponents.Button { Layout.fillWidth: true text: i18nc("global launchers group","Global") checked: parent.group === group checkable: true exclusiveGroup: launchersGroup tooltip: i18n("Use the global set of launchers for this latteView. This group provides launchers synchronization between different views and between different layouts") readonly property int group: Latte.Types.GlobalLaunchers } } } //! END: Launchers Group //! BEGIN: Actions ColumnLayout { spacing: units.smallSpacing Layout.rightMargin: units.smallSpacing * 2 visible: dialog.expertLevel LatteExtraControls.Header { text: i18n("Actions") } GridLayout { columns: 2 Layout.leftMargin: units.smallSpacing * 2 Layout.topMargin: units.smallSpacing enabled: !disableAllWindowsFunctionality PlasmaComponents.Label { text: i18n("Left Click") } PlasmaComponents3.ComboBox { id: leftClickAction Layout.fillWidth: true model: [i18nc("present windows action", "Present Windows"), i18n("Cycle Through Tasks"), i18n("Preview Windows")] currentIndex: { switch(plasmoid.configuration.leftClickAction) { case Latte.Types.PresentWindows: return 0; case Latte.Types.CycleThroughTasks: return 1; case Latte.Types.PreviewWindows: return 2; } return 0; } onCurrentIndexChanged: { switch(currentIndex) { case 0: plasmoid.configuration.leftClickAction = Latte.Types.PresentWindows; break; case 1: plasmoid.configuration.leftClickAction = Latte.Types.CycleThroughTasks; break; case 2: plasmoid.configuration.leftClickAction = Latte.Types.PreviewWindows; break; } } } PlasmaComponents.Label { text: i18n("Middle Click") } PlasmaComponents3.ComboBox { id: middleClickAction Layout.fillWidth: true model: [ i18nc("The click action", "None"), i18n("Close Window or Group"), i18n("New Instance"), i18n("Minimize/Restore Window or Group"), i18n("Cycle Through Tasks"), i18n("Toggle Task Grouping") ] currentIndex: plasmoid.configuration.middleClickAction onCurrentIndexChanged: plasmoid.configuration.middleClickAction = currentIndex } PlasmaComponents.Label { text: i18n("Hover") } PlasmaComponents3.ComboBox { id: hoverAction Layout.fillWidth: true model: [ i18nc("none action", "None"), i18n("Preview Windows"), i18n("Highlight Windows"), i18n("Preview and Highlight Windows"), ] currentIndex: { switch(plasmoid.configuration.hoverAction) { case Latte.Types.NoneAction: return 0; case Latte.Types.PreviewWindows: return 1; case Latte.Types.HighlightWindows: return 2; case Latte.Types.PreviewAndHighlightWindows: return 3; } return 0; } onCurrentIndexChanged: { switch(currentIndex) { case 0: plasmoid.configuration.hoverAction = Latte.Types.NoneAction; break; case 1: plasmoid.configuration.hoverAction = Latte.Types.PreviewWindows; break; case 2: plasmoid.configuration.hoverAction = Latte.Types.HighlightWindows; break; case 3: plasmoid.configuration.hoverAction = Latte.Types.PreviewAndHighlightWindows; break; } } } } RowLayout { Layout.leftMargin: units.smallSpacing * 2 Layout.topMargin: units.smallSpacing spacing: units.smallSpacing enabled: !disableAllWindowsFunctionality PlasmaComponents3.ComboBox { id: modifier Layout.maximumWidth: theme.mSize(theme.defaultFont).width * 5 model: ["Shift", "Ctrl", "Alt", "Meta"] currentIndex: plasmoid.configuration.modifier onCurrentIndexChanged: plasmoid.configuration.modifier = currentIndex } PlasmaComponents.Label { text: "+" } PlasmaComponents3.ComboBox { id: modifierClick Layout.maximumWidth: theme.mSize(theme.defaultFont).width * 10 model: [i18n("Left Click"), i18n("Middle Click"), i18n("Right Click")] currentIndex: plasmoid.configuration.modifierClick onCurrentIndexChanged: plasmoid.configuration.modifierClick = currentIndex } PlasmaComponents.Label { text: "=" } PlasmaComponents3.ComboBox { id: modifierClickAction Layout.fillWidth: true model: [i18nc("The click action", "None"), i18n("Close Window or Group"), i18n("New Instance"), i18n("Minimize/Restore Window or Group"), i18n("Cycle Through Tasks"), i18n("Toggle Task Grouping")] currentIndex: plasmoid.configuration.modifierClickAction onCurrentIndexChanged: plasmoid.configuration.modifierClickAction = currentIndex } } } //! END: Actions //! BEGIN: Actions ColumnLayout { spacing: units.smallSpacing Layout.rightMargin: units.smallSpacing * 2 visible: dialog.expertLevel LatteExtraControls.Header { text: i18n("Recycling") } PlasmaComponents.Button { Layout.leftMargin: units.smallSpacing * 2 Layout.topMargin: units.smallSpacing Layout.fillWidth: true text: i18n("Remove Latte Tasks Applet") enabled: latteView.latteTasksPresent() tooltip: i18n("Remove Latte Tasks plasmoid") onClicked: { latteView.removeTasksPlasmoid(); } } } //! Bottom spacer PlasmaComponents.Label{ id: bottomMarginSpacer text:" " } } }