diff --git a/app/globalshortcuts.cpp b/app/globalshortcuts.cpp index 3278e022..661d664c 100644 --- a/app/globalshortcuts.cpp +++ b/app/globalshortcuts.cpp @@ -1,919 +1,919 @@ /* * 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 "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 // X11 #include #include #include //this code is used by activityswitcher in plasma in order to check if the //user has release all the modifier keys from the globalshortcut namespace { bool isPlatformX11() { static const bool isX11 = QX11Info::isPlatformX11(); return isX11; } // Taken from kwin/tabbox/tabbox.cpp Display *x11_display() { static Display *s_display = nullptr; if (!s_display) { s_display = QX11Info::display(); } return s_display; } bool x11_areKeySymXsDepressed(bool bAll, const uint keySyms[], int nKeySyms) { char keymap[32]; XQueryKeymap(x11_display(), keymap); for (int iKeySym = 0; iKeySym < nKeySyms; iKeySym++) { uint keySymX = keySyms[ iKeySym ]; uchar keyCodeX = XKeysymToKeycode(x11_display(), keySymX); int i = keyCodeX / 8; char mask = 1 << (keyCodeX - (i * 8)); // Abort if bad index value, if (i < 0 || i >= 32) return false; // If ALL keys passed need to be depressed, if (bAll) { if ((keymap[i] & mask) == 0) return false; } else { // If we are looking for ANY key press, and this key is depressed, if (keymap[i] & mask) return true; } } // If we were looking for ANY key press, then none was found, return false, // If we were looking for ALL key presses, then all were found, return true. return bAll; } bool x11_areModKeysDepressed(const QKeySequence &seq) { uint rgKeySyms[10]; int nKeySyms = 0; if (seq.isEmpty()) { return false; } int mod = seq[seq.count() - 1] & Qt::KeyboardModifierMask; if (mod & Qt::SHIFT) { rgKeySyms[nKeySyms++] = XK_Shift_L; rgKeySyms[nKeySyms++] = XK_Shift_R; } if (mod & Qt::CTRL) { rgKeySyms[nKeySyms++] = XK_Control_L; rgKeySyms[nKeySyms++] = XK_Control_R; } if (mod & Qt::ALT) { rgKeySyms[nKeySyms++] = XK_Alt_L; rgKeySyms[nKeySyms++] = XK_Alt_R; } if (mod & Qt::META) { // It would take some code to determine whether the Win key // is associated with Super or Meta, so check for both. // See bug #140023 for details. rgKeySyms[nKeySyms++] = XK_Super_L; rgKeySyms[nKeySyms++] = XK_Super_R; rgKeySyms[nKeySyms++] = XK_Meta_L; rgKeySyms[nKeySyms++] = XK_Meta_R; } return x11_areKeySymXsDepressed(false, rgKeySyms, nKeySyms); } } namespace Latte { const int APPLETEXECUTIONDELAY = 400; GlobalShortcuts::GlobalShortcuts(QObject *parent) : QObject(parent) { m_corona = qobject_cast(parent); if (m_corona) { init(); } m_hideDocksTimer.setSingleShot(true); if (isPlatformX11()) { //in X11 the timer is a poller that checks to see if the modifier keys //from user global shortcut have been released m_hideDocksTimer.setInterval(300); } else { //on wayland in acting just as simple timer that hides the dock afterwards m_hideDocksTimer.setInterval(2500); } connect(&m_hideDocksTimer, &QTimer::timeout, this, &GlobalShortcuts::hideDocksTimerSlot); } GlobalShortcuts::~GlobalShortcuts() { } void GlobalShortcuts::init() { KActionCollection *generalActions = new KActionCollection(m_corona); //show-hide the main dock in the primary screen QAction *showAction = generalActions->addAction(QStringLiteral("show latte dock")); showAction->setText(i18n("Show Dock")); showAction->setShortcut(QKeySequence(Qt::META + '`')); KGlobalAccel::setGlobalShortcut(showAction, QKeySequence(Qt::META + '`')); connect(showAction, &QAction::triggered, this, [this]() { showDocks(); }); //show-cycle between Latte settings windows QAction *settingsAction = generalActions->addAction(QStringLiteral("show dock settings")); settingsAction->setText(i18n("Show Dock Settings")); KGlobalAccel::setGlobalShortcut(settingsAction, QKeySequence(Qt::META + Qt::Key_A)); connect(settingsAction, &QAction::triggered, this, [this] { 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_corona->layoutManager()->showLatteSettingsDialog(Dock::LayoutPage); + 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_corona->layoutManager()->showLatteSettingsDialog(Dock::PreferencesPage); + 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..."; 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] { 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..."; 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] { activateEntry(i, static_cast(Qt::CTRL)); }); } m_singleMetaAction = new QAction(this); m_singleMetaAction->setShortcut(QKeySequence(Qt::META)); } //! Activate launcher menu through dbus interface void GlobalShortcuts::activateLauncherMenu() { 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()) { m_lastInvokedAction = m_singleMetaAction; m_hideDocks.clear(); m_hideDocks.append(view); view->visibility()->setBlockHiding(true); m_hideDocksTimer.start(); //! delay the execution in order to show first the dock QTimer::singleShot(APPLETEXECUTIONDELAY, [this, view, applet]() { view->toggleAppletExpanded(applet->id()); }); } 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("setShowTasksNumbers(QVariant)"); if (methodIndex == -1 || (methodIndex2 == -1 && meta.pluginId() == "org.kde.latte.plasmoid")) { continue; } int showMethodIndex = -1; if (!m_calledItems.contains(item)) { m_calledItems.append(item); m_methodsShowNumbers.append(metaObject->method(methodIndex)); showMethodIndex = m_methodsShowNumbers.count() - 1; } else { showMethodIndex = m_methodsShowNumbers.indexOf(metaObject->method(methodIndex)); } QMetaMethod method = metaObject->method(methodIndex); if (method.invoke(item, Q_ARG(QVariant, index - 1))) { if (methodIndex2 != -1) { m_methodsShowNumbers[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("setShowAppletsNumbers(QVariant,QVariant,QVariant)"); if (methodIndex == -1 || (methodIndex2 == -1)) { continue; } int appLauncher = m_corona->universalSettings()->metaForwardedToLatte() ? applicationLauncherId(view->containment()) : -1; int showMethodIndex = -1; if (!m_calledItems.contains(item)) { m_calledItems.append(item); m_methodsShowNumbers.append(metaObject->method(methodIndex2)); showMethodIndex = m_methodsShowNumbers.count() - 1; } else { showMethodIndex = m_methodsShowNumbers.indexOf(metaObject->method(methodIndex2)); } QMetaMethod method = metaObject->method(methodIndex); if (view->visibility()->isHidden()) { //! delay the execution in order to show first the dock if (m_methodsShowNumbers[showMethodIndex].invoke(item, Q_ARG(QVariant, true), Q_ARG(QVariant, true), Q_ARG(QVariant, appLauncher))) { 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))) { m_methodsShowNumbers[showMethodIndex].invoke(item, Q_ARG(QVariant, true), Q_ARG(QVariant, true), Q_ARG(QVariant, appLauncher)); return true; } } } } } return false; } //! Activate task manager entry void GlobalShortcuts::activateEntry(int index, Qt::Key modifier) { 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)) || (activateLatteEntryAtContainment(view, index, modifier))) { if (!m_hideDocks.contains(view)) { m_hideDocks.append(view); } view->visibility()->setBlockHiding(true); m_hideDocksTimer.start(); return; } } } //! update badge for specific dock item void GlobalShortcuts::updateDockItemBadge(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::isCapableToShowAppletsNumbers(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("setShowAppletsNumbers(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::showDocks() { m_lastInvokedAction = dynamic_cast(sender()); auto invokeShowNumbers = [this](const Plasma::Containment * c) { 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("setShowAppletsNumbers(QVariant,QVariant,QVariant)"); if (methodIndex == -1) { continue; } int appLauncher = m_corona->universalSettings()->metaForwardedToLatte() ? applicationLauncherId(c) : -1; int showMethodIndex = -1; if (!m_calledItems.contains(item)) { m_calledItems.append(item); m_methodsShowNumbers.append(metaObject->method(methodIndex)); showMethodIndex = m_methodsShowNumbers.count() - 1; } else { showMethodIndex = m_methodsShowNumbers.indexOf(metaObject->method(methodIndex)); } if (m_methodsShowNumbers[showMethodIndex].invoke(item, Q_ARG(QVariant, true), Q_ARG(QVariant, true), Q_ARG(QVariant, appLauncher))) { return true; } } } } return false; }; auto invokeShowOnlyMeta = [this](const Plasma::Containment * c) { 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("setShowAppletsNumbers(QVariant,QVariant,QVariant)"); if (methodIndex == -1) { continue; } int appLauncher = m_corona->universalSettings()->metaForwardedToLatte() ? applicationLauncherId(c) : -1; int showMethodIndex = -1; if (!m_calledItems.contains(item)) { m_calledItems.append(item); m_methodsShowNumbers.append(metaObject->method(methodIndex)); showMethodIndex = m_methodsShowNumbers.count() - 1; } else { showMethodIndex = m_methodsShowNumbers.indexOf(metaObject->method(methodIndex)); } if (m_methodsShowNumbers[showMethodIndex].invoke(item, Q_ARG(QVariant, false), 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 && isCapableToShowAppletsNumbers(view)) { viewWithTasks = view; } if (!viewWithMeta && m_corona->universalSettings()->metaForwardedToLatte() && applicationLauncherId(view->containment()) > -1) { viewWithMeta = view; } } bool dockFound{false}; if (!m_hideDocksTimer.isActive()) { m_hideDocks.clear(); } if (viewWithTasks || viewWithMeta) { m_calledItems.clear(); m_methodsShowNumbers.clear(); } if (viewWithTasks && invokeShowNumbers(viewWithTasks->containment())) { dockFound = true; if (!m_hideDocksTimer.isActive()) { m_hideDocks.append(viewWithTasks); viewWithTasks->visibility()->setBlockHiding(true); } } if (viewWithMeta && viewWithMeta != viewWithTasks && invokeShowOnlyMeta(viewWithMeta->containment())) { dockFound = true; if (!m_hideDocksTimer.isActive()) { m_hideDocks.append(viewWithMeta); viewWithMeta->visibility()->setBlockHiding(true); } } if (dockFound) { if (!m_hideDocksTimer.isActive()) { m_hideDocksTimer.start(); } else { m_hideDocksTimer.stop(); hideDocksTimerSlot(); } } } bool GlobalShortcuts::docksToHideAreValid() { foreach (auto view, m_hideDocks) { if (!m_corona->layoutManager()->latteViewExists(view)) { return false; } } return true; } bool GlobalShortcuts::dockAtLowerScreenPriority(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() << "dockAtLowerScreenPriority : shouldn't had reached here..."; return false; } bool GlobalShortcuts::dockAtLowerEdgePriority(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 docks; //! create a docks list to sorted out for (auto it = views->constBegin(), end = views->constEnd(); it != end; ++it) { docks.append(it.value()); } qDebug() << " -------- "; for (int i = 0; i < docks.count(); ++i) { qDebug() << i << ". " << docks[i]->screen()->name() << " - " << docks[i]->location(); } //! sort the docks based on screens and edges priorities //! docks on primary screen have higher priority and //! for docks in the same screen the priority goes to //! Bottom,Left,Top,Right for (int i = 0; i < docks.size(); ++i) { for (int j = 0; j < docks.size() - i - 1; ++j) { if (dockAtLowerScreenPriority(docks[j], docks[j + 1]) || (docks[j]->screen() == docks[j + 1]->screen() && dockAtLowerEdgePriority(docks[j], docks[j + 1]))) { Latte::View *temp = docks[j + 1]; docks[j + 1] = docks[j]; docks[j] = temp; } } } Latte::View *highestPriorityView{nullptr}; for (int i = 0; i < docks.size(); ++i) { if (docks[i]->isPreferredForShortcuts()) { highestPriorityView = docks[i]; docks.removeAt(i); break; } } if (highestPriorityView) { docks.prepend(highestPriorityView); } qDebug() << " -------- sorted -----"; for (int i = 0; i < docks.count(); ++i) { qDebug() << i << ". " << docks[i]->isPreferredForShortcuts() << " - " << docks[i]->screen()->name() << " - " << docks[i]->location(); } return docks; } void GlobalShortcuts::showSettings() { QList docks = sortedViewsList(m_corona->layoutManager()->currentLatteViews()); //! find which is the next dock to show its settings if (docks.count() > 0) { int openSettings = -1; //! check if there is a dock with opened settings window for (int i = 0; i < docks.size(); ++i) { if (docks[i]->settingsWindowIsShown()) { openSettings = i; break; } } if (openSettings >= 0 && docks.count() > 1) { openSettings = openSettings + 1; if (openSettings >= docks.size()) { openSettings = 0; } docks[openSettings]->showSettingsWindow(); } else { docks[0]->showSettingsWindow(); } } } void GlobalShortcuts::hideDocksTimerSlot() { if (!m_lastInvokedAction || m_hideDocks.count() == 0) { return; } // qDebug() << "MEMORY ::: " << m_hideDocks.count() << " _ " << m_calledItems.count() << " _ " << m_methodsShowNumbers.count(); if (isPlatformX11()) { if (!x11_areModKeysDepressed(m_lastInvokedAction->shortcut())) { m_lastInvokedAction = Q_NULLPTR; if (docksToHideAreValid()) { foreach (auto latteView, m_hideDocks) { latteView->visibility()->setBlockHiding(false); } if (m_calledItems.count() > 0) { for (int i = 0; i < m_calledItems.count(); ++i) { m_methodsShowNumbers[i].invoke(m_calledItems[i], Q_ARG(QVariant, false), Q_ARG(QVariant, false), Q_ARG(QVariant, -1)); } } } m_hideDocks.clear(); m_calledItems.clear(); m_methodsShowNumbers.clear(); return; } else { m_hideDocksTimer.start(); } } else { // TODO: This is needs to be fixed in wayland m_lastInvokedAction = Q_NULLPTR; if (docksToHideAreValid()) { foreach (auto latteView, m_hideDocks) { latteView->visibility()->setBlockHiding(false); } if (m_calledItems.count() > 0) { for (int i = 0; i < m_calledItems.count(); ++i) { m_methodsShowNumbers[i].invoke(m_calledItems[i], Q_ARG(QVariant, false), Q_ARG(QVariant, false), Q_ARG(QVariant, -1)); } } } m_hideDocks.clear(); m_calledItems.clear(); m_methodsShowNumbers.clear(); } } } #include "moc_globalshortcuts.cpp" diff --git a/app/globalshortcuts.h b/app/globalshortcuts.h index dccd23bf..f68e2d06 100644 --- a/app/globalshortcuts.h +++ b/app/globalshortcuts.h @@ -1,89 +1,89 @@ /* * 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 . */ #ifndef GLOBALSHORTCUTS_H #define GLOBALSHORTCUTS_H // local -#include "../liblattedock/dock.h" +#include "../liblatte2/types.h" // Qt #include #include #include namespace Plasma { class Containment; } namespace Latte { class Corona; class View; } namespace Latte { class GlobalShortcuts : public QObject { Q_OBJECT public: GlobalShortcuts(QObject *parent = nullptr); ~GlobalShortcuts() override; void activateLauncherMenu(); void updateDockItemBadge(QString identifier, QString value); private slots: void hideDocksTimerSlot(); private: void init(); void activateEntry(int index, Qt::Key modifier); void showDocks(); void showSettings(); bool activateLatteEntryAtContainment(const Latte::View *view, int index, Qt::Key modifier); bool activatePlasmaTaskManagerEntryAtContainment(const Plasma::Containment *c, int index, Qt::Key modifier); bool dockAtLowerEdgePriority(Latte::View *test, Latte::View *base); bool dockAtLowerScreenPriority(Latte::View *test, Latte::View *base); bool docksToHideAreValid(); bool isCapableToShowAppletsNumbers(Latte::View *view); int applicationLauncherId(const Plasma::Containment *c); QList sortedViewsList(QHash *views); QAction *m_lastInvokedAction; //!it is used when the dock is hidden in order to delay the app launcher showing QAction *m_singleMetaAction; QTimer m_hideDocksTimer; QList m_hideDocks; QList m_calledItems; QList m_methodsShowNumbers; Latte::Corona *m_corona{nullptr}; }; } #endif // GLOBALSHORTCUTS_H diff --git a/app/importer.cpp b/app/importer.cpp index eb62f137..8032fa25 100644 --- a/app/importer.cpp +++ b/app/importer.cpp @@ -1,598 +1,598 @@ /* * 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 "importer.h" // local #include "lattecorona.h" #include "layoutmanager.h" #include "layout.h" #include "screenpool.h" #include "settings/universalsettings.h" -#include "../liblattedock/dock.h" +#include "../liblatte2/types.h" // Qt #include #include // KDE #include #include #include #include #include #include namespace Latte { Importer::Importer(QObject *parent) : QObject(parent) { m_manager = qobject_cast(parent); } Importer::~Importer() { } bool Importer::updateOldConfiguration() { QFile oldAppletsFile(QDir::homePath() + "/.config/lattedock-appletsrc"); if (!oldAppletsFile.exists()) { return false; } //! import standard old configuration and create the relevant layouts importOldLayout(QDir::homePath() + "/.config/lattedock-appletsrc", i18n("My Layout")); importOldLayout(QDir::homePath() + "/.config/lattedock-appletsrc", i18n("Alternative"), true); QFile extFile(QDir::homePath() + "/.config/lattedockextrc"); //! import also the old user layouts into the new architecture if (extFile.exists()) { KSharedConfigPtr extFileConfig = KSharedConfig::openConfig(extFile.fileName()); KConfigGroup externalSettings = KConfigGroup(extFileConfig, "External"); QStringList userLayouts = externalSettings.readEntry("userLayouts", QStringList()); foreach (auto userConfig, userLayouts) { qDebug() << "user layout : " << userConfig; importOldConfiguration(userConfig); } } m_manager->corona()->universalSettings()->setCurrentLayoutName(i18n("My Layout")); m_manager->corona()->universalSettings()->setVersion(2); return true; } bool Importer::importOldLayout(QString oldAppletsPath, QString newName, bool alternative, QString exportDirectory) { QString newLayoutPath = layoutCanBeImported(oldAppletsPath, newName, exportDirectory); qDebug() << "New Layout Should be created: " << newLayoutPath; KSharedConfigPtr oldFile = KSharedConfig::openConfig(oldAppletsPath); KSharedConfigPtr newFile = KSharedConfig::openConfig(newLayoutPath); KConfigGroup containments = KConfigGroup(oldFile, "Containments"); KConfigGroup copiedContainments = KConfigGroup(newFile, "Containments"); QList systrays; bool atLeastOneContainmentWasFound{false}; //! first copy the latte containments that correspond to the correct session //! and find also the systrays that should be copied also foreach (auto containmentId, containments.groupList()) { KConfigGroup containmentGroup = containments.group(containmentId); QString plugin = containmentGroup.readEntry("plugin", QString()); - Dock::SessionType session = (Dock::SessionType)containmentGroup.readEntry("session", (int)Dock::DefaultSession); + Types::SessionType session = (Types::SessionType)containmentGroup.readEntry("session", (int)Types::DefaultSession); bool shouldImport = false; - if (plugin == "org.kde.latte.containment" && session == Dock::DefaultSession && !alternative) { + if (plugin == "org.kde.latte.containment" && session == Types::DefaultSession && !alternative) { qDebug() << containmentId << " - " << plugin << " - " << session; shouldImport = true; - } else if (plugin == "org.kde.latte.containment" && session == Dock::AlternativeSession && alternative) { + } else if (plugin == "org.kde.latte.containment" && session == Types::AlternativeSession && alternative) { qDebug() << containmentId << " - " << plugin << " - " << session; shouldImport = true; } // this latte containment should be imported if (shouldImport) { auto applets = containments.group(containmentId).group("Applets"); foreach (auto applet, applets.groupList()) { KConfigGroup appletSettings = applets.group(applet).group("Configuration"); int systrayId = appletSettings.readEntry("SystrayContainmentId", "-1").toInt(); if (systrayId != -1) { systrays.append(systrayId); qDebug() << "systray was found in the containment..."; break; } } KConfigGroup newContainment = copiedContainments.group(containmentId); containmentGroup.copyTo(&newContainment); atLeastOneContainmentWasFound = true; } } //! not even one latte containment was found for that layout so we must break //! the code here if (!atLeastOneContainmentWasFound) { return false; } //! copy also the systrays that were discovered foreach (auto containmentId, containments.groupList()) { int cId = containmentId.toInt(); if (systrays.contains(cId)) { KConfigGroup containmentGroup = containments.group(containmentId); KConfigGroup newContainment = copiedContainments.group(containmentId); containmentGroup.copyTo(&newContainment); } } copiedContainments.sync(); KConfigGroup oldGeneralSettings = KConfigGroup(oldFile, "General"); QStringList layoutLaunchers; if (!alternative) { layoutLaunchers = oldGeneralSettings.readEntry("globalLaunchers_default", QStringList()); } else { layoutLaunchers = oldGeneralSettings.readEntry("globalLaunchers_alternative", QStringList()); } //! update also the layout settings correctly Layout newLayout(this, newLayoutPath, newName); newLayout.setVersion(2); newLayout.setLaunchers(layoutLaunchers); newLayout.setShowInMenu(true); if (alternative) { newLayout.setColor("purple"); } else { newLayout.setColor("blue"); } return true; } QString Importer::layoutCanBeImported(QString oldAppletsPath, QString newName, QString exportDirectory) { QFile oldAppletsrc(oldAppletsPath); //! old file doesn't exist if (!oldAppletsrc.exists()) { return QString(); } KSharedConfigPtr lConfig = KSharedConfig::openConfig(oldAppletsPath); KConfigGroup m_layoutGroup = KConfigGroup(lConfig, "LayoutSettings"); int layoutVersion = m_layoutGroup.readEntry("version", 1); //! old file layout appears to not be old as its version is >=2 if (layoutVersion >= 2) { return QString(); } QDir layoutDir(exportDirectory.isNull() ? QDir::homePath() + "/.config/latte" : exportDirectory); if (!layoutDir.exists() && exportDirectory.isNull()) { QDir(QDir::homePath() + "/.config").mkdir("latte"); } //! set up the new layout name if (newName.isEmpty()) { int extension = oldAppletsrc.fileName().lastIndexOf(".latterc"); if (extension > 0) { //! remove the last 8 characters that contain the extension newName = oldAppletsrc.fileName().remove(extension, 8); } else { newName = oldAppletsrc.fileName(); } } QString newLayoutPath = layoutDir.absolutePath() + "/" + newName + ".layout.latte"; QFile newLayoutFile(newLayoutPath); QStringList filter; filter.append(QString(newName + "*.layout.latte")); QStringList files = layoutDir.entryList(filter, QDir::Files | QDir::NoSymLinks); //! if the newLayout already exists provide a newName that doesn't if (files.count() >= 1) { int newCounter = files.count() + 1; newLayoutPath = layoutDir.absolutePath() + "/" + newName + "-" + QString::number(newCounter) + ".layout.latte"; } return newLayoutPath; } bool Importer::importOldConfiguration(QString oldConfigPath, QString newName) { QFile oldConfigFile(oldConfigPath); if (!oldConfigFile.exists()) { return false; } KTar archive(oldConfigPath, QStringLiteral("application/x-tar")); archive.open(QIODevice::ReadOnly); if (!archive.isOpen()) { return false; } auto rootDir = archive.directory(); QTemporaryDir uniqueTempDir; QDir tempDir{uniqueTempDir.path()}; qDebug() << "temp layout directory : " << tempDir.absolutePath(); if (rootDir) { if (!tempDir.exists()) tempDir.mkpath(tempDir.absolutePath()); foreach (auto &name, rootDir->entries()) { auto fileEntry = rootDir->file(name); if (fileEntry && (fileEntry->name() == "lattedockrc" || fileEntry->name() == "lattedock-appletsrc")) { if (!fileEntry->copyTo(tempDir.absolutePath())) { qInfo() << i18nc("import/export config", "The extracted file could not be copied!!!"); archive.close(); return false; } } else { qInfo() << i18nc("import/export config", "The file has a wrong format!!!"); archive.close(); return false; } } } else { qInfo() << i18nc("import/export config", "The temp directory could not be created!!!"); archive.close(); return false; } //! only if the above has passed we must process the files QString appletsPath(tempDir.absolutePath() + "/lattedock-appletsrc"); QString screensPath(tempDir.absolutePath() + "/lattedockrc"); if (!QFile(appletsPath).exists() || !QFile(screensPath).exists()) { return false; } if (newName.isEmpty()) { int lastSlash = oldConfigPath.lastIndexOf("/"); newName = oldConfigPath.remove(0, lastSlash + 1); int ext = newName.lastIndexOf(".latterc"); newName = newName.remove(ext, 8); } if (!importOldLayout(appletsPath, newName)) { return false; } //! the old configuration contains also screen values, these must be updated also KSharedConfigPtr oldScreensConfig = KSharedConfig::openConfig(screensPath); KConfigGroup m_screensGroup = KConfigGroup(oldScreensConfig, "ScreenConnectors"); //restore the known ids to connector mappings foreach (const QString &key, m_screensGroup.keyList()) { QString connector = m_screensGroup.readEntry(key, QString()); int id = key.toInt(); if (id >= 10 && !m_manager->corona()->screenPool()->knownIds().contains(id)) { m_manager->corona()->screenPool()->insertScreenMapping(id, connector); } } return true; } bool Importer::exportFullConfiguration(QString file) { if (QFile::exists(file) && !QFile::remove(file)) { return false; } KTar archive(file, QStringLiteral("application/x-tar")); if (!archive.open(QIODevice::WriteOnly)) { return false; } archive.addLocalFile(QString(QDir::homePath() + "/.config/lattedockrc"), QStringLiteral("lattedockrc")); foreach (auto layoutName, availableLayouts()) { archive.addLocalFile(layoutFilePath(layoutName), QString("latte/" + layoutName + ".layout.latte")); } //archive.addLocalDirectory(QString(QDir::homePath() + "/.config/latte"), QStringLiteral("latte")); archive.close(); return true; } Importer::LatteFileVersion Importer::fileVersion(QString file) { if (!QFile::exists(file)) return UnknownFileType; if (file.endsWith(".layout.latte")) { KSharedConfigPtr lConfig = KSharedConfig::openConfig(QFileInfo(file).absoluteFilePath()); KConfigGroup layoutGroup = KConfigGroup(lConfig, "LayoutSettings"); int version = layoutGroup.readEntry("version", 1); if (version == 2) return Importer::LayoutVersion2; else return Importer::UnknownFileType; } if (!file.endsWith(".latterc")) { return Importer::UnknownFileType; } KTar archive(file, QStringLiteral("application/x-tar")); archive.open(QIODevice::ReadOnly); //! if the file isnt a tar archive if (!archive.isOpen()) { return Importer::UnknownFileType; } QTemporaryDir archiveTempDir; bool version1rc = false; bool version1applets = false; bool version2rc = false; bool version2LatteDir = false; bool version2layout = false; archive.directory()->copyTo(archiveTempDir.path()); //rc file QString rcFile(archiveTempDir.path() + "/lattedockrc"); if (QFile(rcFile).exists()) { KSharedConfigPtr lConfig = KSharedConfig::openConfig(rcFile); KConfigGroup universalGroup = KConfigGroup(lConfig, "UniversalSettings"); int version = universalGroup.readEntry("version", 1); if (version == 1) { version1rc = true; } else if (version == 2) { version2rc = true; } } //applets file QString appletsFile(archiveTempDir.path() + "/lattedock-appletsrc"); if (QFile(appletsFile).exists() && version1rc) { KSharedConfigPtr lConfig = KSharedConfig::openConfig(appletsFile); KConfigGroup generalGroup = KConfigGroup(lConfig, "LayoutSettings"); int version = generalGroup.readEntry("version", 1); if (version == 1) { version1applets = true; } else if (version == 2) { version2layout = true; } } //latte directory QString latteDir(archiveTempDir.path() + "/latte"); if (QDir(latteDir).exists()) { version2LatteDir = true; } if (version1applets && version1applets) { return ConfigVersion1; } else if (version2rc && version2LatteDir) { return ConfigVersion2; } return Importer::UnknownFileType; } bool Importer::importHelper(QString fileName) { LatteFileVersion version = fileVersion(fileName); if ((version != ConfigVersion1) && (version != ConfigVersion2)) { return false; } KTar archive(fileName, QStringLiteral("application/x-tar")); archive.open(QIODevice::ReadOnly); if (!archive.isOpen()) { return false; } QString latteDirPath(QDir::homePath() + "/.config/latte"); QDir latteDir(latteDirPath); if (latteDir.exists()) { latteDir.removeRecursively(); } archive.directory()->copyTo(QString(QDir::homePath() + "/.config")); return true; } QString Importer::importLayoutHelper(QString fileName) { LatteFileVersion version = fileVersion(fileName); if (version != LayoutVersion2) { return QString(); } QString newLayoutName = Layout::layoutName(fileName); newLayoutName = uniqueLayoutName(newLayoutName); QString newPath = QDir::homePath() + "/.config/latte/" + newLayoutName + ".layout.latte"; QFile(fileName).copy(newPath); QFileInfo newFileInfo(newPath); if (newFileInfo.exists() && !newFileInfo.isWritable()) { QFile(newPath).setPermissions(QFileDevice::ReadUser | QFileDevice::WriteUser | QFileDevice::ReadGroup | QFileDevice::ReadOther); } return newLayoutName; } QStringList Importer::availableLayouts() { QDir layoutDir(QDir::homePath() + "/.config/latte"); QStringList filter; filter.append(QString("*.layout.latte")); QStringList files = layoutDir.entryList(filter, QDir::Files | QDir::NoSymLinks); QStringList layoutNames; foreach (auto file, files) { layoutNames.append(Layout::layoutName(file)); } return layoutNames; } QString Importer::nameOfConfigFile(const QString &fileName) { int lastSlash = fileName.lastIndexOf("/"); QString tempLayoutFile = fileName; QString layoutName = tempLayoutFile.remove(0, lastSlash + 1); int ext = layoutName.lastIndexOf(".latterc"); layoutName = layoutName.remove(ext, 8); return layoutName; } bool Importer::layoutExists(QString layoutName) { return QFile::exists(layoutFilePath(layoutName)); } QString Importer::layoutFilePath(QString layoutName) { return QString(QDir::homePath() + "/.config/latte/" + layoutName + ".layout.latte"); } QString Importer::uniqueLayoutName(QString name) { int pos_ = name.lastIndexOf(QRegExp(QString("[-][0-9]+"))); if (layoutExists(name) && pos_ > 0) { name = name.left(pos_); } int i = 2; QString namePart = name; while (layoutExists(name)) { name = namePart + "-" + QString::number(i); i++; } return name; } QStringList Importer::checkRepairMultipleLayoutsLinkedFile() { QString linkedFilePath = QDir::homePath() + "/.config/latte/" + Layout::MultipleLayoutsName + ".layout.latte"; KSharedConfigPtr filePtr = KSharedConfig::openConfig(linkedFilePath); KConfigGroup linkedContainments = KConfigGroup(filePtr, "Containments"); //! layoutName and its Containments QHash linkedLayoutContainmentGroups; foreach (auto cId, linkedContainments.groupList()) { QString layoutName = linkedContainments.group(cId).readEntry("layoutId", QString()); if (!layoutName.isEmpty()) { qDebug() << layoutName; linkedLayoutContainmentGroups[layoutName].append(cId); linkedContainments.group(cId).writeEntry("layoutId", QString()); } } QStringList updatedLayouts; foreach (auto layoutName, linkedLayoutContainmentGroups.uniqueKeys()) { if (layoutName != Layout::MultipleLayoutsName && layoutExists(layoutName)) { updatedLayouts << layoutName; KSharedConfigPtr layoutFilePtr = KSharedConfig::openConfig(layoutFilePath(layoutName)); KConfigGroup origLayoutContainments = KConfigGroup(layoutFilePtr, "Containments"); //Clear old containments origLayoutContainments.deleteGroup(); //Update containments foreach (auto cId, linkedLayoutContainmentGroups[layoutName]) { KConfigGroup newContainment = origLayoutContainments.group(cId); linkedContainments.group(cId).copyTo(&newContainment); linkedContainments.group(cId).deleteGroup(); } origLayoutContainments.sync(); } } //! clear all remaining ghost containments foreach (auto cId, linkedContainments.groupList()) { linkedContainments.group(cId).deleteGroup(); } linkedContainments.sync(); return updatedLayouts; } } diff --git a/app/lattecorona.cpp b/app/lattecorona.cpp index 1f97238b..6a8fbf7a 100644 --- a/app/lattecorona.cpp +++ b/app/lattecorona.cpp @@ -1,955 +1,955 @@ /* * 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 "lattecorona.h" // local #include "alternativeshelper.h" #include "globalshortcuts.h" #include "importer.h" #include "lattedockadaptor.h" #include "launcherssignals.h" #include "layoutmanager.h" #include "plasmathemeextended.h" #include "screenpool.h" #include "packageplugins/shell/lattepackage.h" #include "settings/universalsettings.h" #include "view/view.h" #include "wm/abstractwindowinterface.h" #include "wm/waylandinterface.h" #include "wm/xwindowinterface.h" // Qt #include #include #include #include #include #include #include #include #include // Plasma #include #include #include #include // KDE #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Latte { Corona::Corona(bool defaultLayoutOnStartup, QString layoutNameOnStartUp, int userSetMemoryUsage, QObject *parent) : Plasma::Corona(parent), m_defaultLayoutOnStartup(defaultLayoutOnStartup), m_userSetMemoryUsage(userSetMemoryUsage), m_layoutNameOnStartUp(layoutNameOnStartUp), m_activityConsumer(new KActivities::Consumer(this)), m_screenPool(new ScreenPool(KSharedConfig::openConfig(), this)), m_globalShortcuts(new GlobalShortcuts(this)), m_universalSettings(new UniversalSettings(KSharedConfig::openConfig(), this)), m_themeExtended(new PlasmaThemeExtended(KSharedConfig::openConfig(), this)), m_layoutManager(new LayoutManager(this)) { //! create the window manager if (KWindowSystem::isPlatformWayland()) { m_wm = new WaylandInterface(this); } else { m_wm = new XWindowInterface(this); } setupWaylandIntegration(); KPackage::Package package(new Latte::Package(this)); m_screenPool->load(); if (!package.isValid()) { qWarning() << staticMetaObject.className() << "the package" << package.metadata().rawData() << "is invalid!"; return; } else { qDebug() << staticMetaObject.className() << "the package" << package.metadata().rawData() << "is valid!"; } setKPackage(package); //! universal settings / extendedtheme must be loaded after the package has been set m_universalSettings->load(); m_themeExtended->load(); qmlRegisterTypes(); if (m_activityConsumer && (m_activityConsumer->serviceStatus() == KActivities::Consumer::Running)) { load(); } connect(m_activityConsumer, &KActivities::Consumer::serviceStatusChanged, this, &Corona::load); m_viewsScreenSyncTimer.setSingleShot(true); m_viewsScreenSyncTimer.setInterval(m_universalSettings->screenTrackerInterval()); connect(&m_viewsScreenSyncTimer, &QTimer::timeout, this, &Corona::syncLatteViewsToScreens); connect(m_universalSettings, &UniversalSettings::screenTrackerIntervalChanged, this, [this]() { m_viewsScreenSyncTimer.setInterval(m_universalSettings->screenTrackerInterval()); }); //! Dbus adaptor initialization new LatteDockAdaptor(this); QDBusConnection dbus = QDBusConnection::sessionBus(); dbus.registerObject(QStringLiteral("/Latte"), this); } Corona::~Corona() { //! BEGIN: Give the time to slide-out views when closing m_layoutManager->hideAllViews(); //! Don't delay the destruction under wayland in any case //! because it creates a crash with kwin effects //! https://bugs.kde.org/show_bug.cgi?id=392890 if (!KWindowSystem::isPlatformWayland()) { QTimer::singleShot(400, [this]() { m_quitTimedEnded = true; }); while (!m_quitTimedEnded) { QGuiApplication::processEvents(QEventLoop::AllEvents, 50); } } //! END: slide-out views when closing m_viewsScreenSyncTimer.stop(); - if (m_layoutManager->memoryUsage() == Dock::SingleLayout) { + if (m_layoutManager->memoryUsage() == Types::SingleLayout) { cleanConfig(); } qDebug() << "Latte Corona - unload: containments ..."; m_layoutManager->unload(); m_wm->deleteLater(); m_globalShortcuts->deleteLater(); m_layoutManager->deleteLater(); m_screenPool->deleteLater(); m_universalSettings->deleteLater(); m_themeExtended->deleteLater(); disconnect(m_activityConsumer, &KActivities::Consumer::serviceStatusChanged, this, &Corona::load); delete m_activityConsumer; qDebug() << "Latte Corona - deleted..."; } void Corona::load() { if (m_activityConsumer && (m_activityConsumer->serviceStatus() == KActivities::Consumer::Running) && m_activitiesStarting) { disconnect(m_activityConsumer, &KActivities::Consumer::serviceStatusChanged, this, &Corona::load); m_layoutManager->load(); m_activitiesStarting = false; connect(qGuiApp, &QGuiApplication::primaryScreenChanged, this, &Corona::primaryOutputChanged, Qt::UniqueConnection); connect(QApplication::desktop(), &QDesktopWidget::screenCountChanged, this, &Corona::screenCountChanged); connect(m_screenPool, &ScreenPool::primaryPoolChanged, this, &Corona::screenCountChanged); QString assignedLayout = m_layoutManager->shouldSwitchToLayout(m_activityConsumer->currentActivity()); QString loadLayoutName = ""; if (!m_defaultLayoutOnStartup && m_layoutNameOnStartUp.isEmpty()) { if (!assignedLayout.isEmpty() && assignedLayout != m_universalSettings->currentLayoutName()) { loadLayoutName = assignedLayout; } else { loadLayoutName = m_universalSettings->currentLayoutName(); } if (!m_layoutManager->layoutExists(loadLayoutName)) { loadLayoutName = m_layoutManager->defaultLayoutName(); m_layoutManager->importDefaultLayout(false); } } else if (m_defaultLayoutOnStartup) { loadLayoutName = m_layoutManager->importer()->uniqueLayoutName(m_layoutManager->defaultLayoutName()); m_layoutManager->importDefaultLayout(true); } else { loadLayoutName = m_layoutNameOnStartUp; } if (m_userSetMemoryUsage != -1 && !KWindowSystem::isPlatformWayland()) { - Dock::LayoutsMemoryUsage usage = static_cast(m_userSetMemoryUsage); + Types::LayoutsMemoryUsage usage = static_cast(m_userSetMemoryUsage); m_universalSettings->setLayoutsMemoryUsage(usage); } if (KWindowSystem::isPlatformWayland()) { - m_universalSettings->setLayoutsMemoryUsage(Dock::SingleLayout); + m_universalSettings->setLayoutsMemoryUsage(Types::SingleLayout); } m_layoutManager->loadLayoutOnStartup(loadLayoutName); //! load screens signals such screenGeometryChanged in order to support //! plasmoid.screenGeometry properly for (QScreen *screen : qGuiApp->screens()) { addOutput(screen); } connect(qGuiApp, &QGuiApplication::screenAdded, this, &Corona::addOutput, Qt::UniqueConnection); } } void Corona::unload() { qDebug() << "unload: removing containments..."; while (!containments().isEmpty()) { //deleting a containment will remove it from the list due to QObject::destroyed connect in Corona //this form doesn't crash, while qDeleteAll(containments()) does delete containments().first(); } } void Corona::setupWaylandIntegration() { if (!KWindowSystem::isPlatformWayland()) { return; } using namespace KWayland::Client; auto connection = ConnectionThread::fromApplication(this); if (!connection) { return; } Registry *registry{new Registry(this)}; registry->create(connection); connect(registry, &Registry::plasmaShellAnnounced, this , [this, registry](quint32 name, quint32 version) { m_waylandCorona = registry->createPlasmaShell(name, version, this); }); QObject::connect(registry, &KWayland::Client::Registry::plasmaWindowManagementAnnounced, [this, registry](quint32 name, quint32 version) { KWayland::Client::PlasmaWindowManagement *pwm = registry->createPlasmaWindowManagement(name, version, this); WaylandInterface *wI = qobject_cast(m_wm); if (wI) { wI->initWindowManagement(pwm); } }); registry->setup(); connection->roundtrip(); } KWayland::Client::PlasmaShell *Corona::waylandCoronaInterface() const { return m_waylandCorona; } void Corona::cleanConfig() { auto containmentsEntries = config()->group("Containments"); bool changed = false; foreach (auto cId, containmentsEntries.groupList()) { if (!containmentExists(cId.toUInt())) { //cleanup obsolete containments containmentsEntries.group(cId).deleteGroup(); changed = true; qDebug() << "obsolete containment configuration deleted:" << cId; } else { //cleanup obsolete applets of running containments auto appletsEntries = containmentsEntries.group(cId).group("Applets"); foreach (auto appletId, appletsEntries.groupList()) { if (!appletExists(cId.toUInt(), appletId.toUInt())) { appletsEntries.group(appletId).deleteGroup(); changed = true; qDebug() << "obsolete applet configuration deleted:" << appletId; } } } } if (changed) { config()->sync(); qDebug() << "configuration file cleaned..."; } } bool Corona::containmentExists(uint id) const { foreach (auto containment, containments()) { if (id == containment->id()) { return true; } } return false; } bool Corona::appletExists(uint containmentId, uint appletId) const { Plasma::Containment *containment = nullptr; foreach (auto cont, containments()) { if (containmentId == cont->id()) { containment = cont; break; } } if (!containment) { return false; } foreach (auto applet, containment->applets()) { if (applet->id() == appletId) { return true; } } return false; } KActivities::Consumer *Corona::activitiesConsumer() const { return m_activityConsumer; } ScreenPool *Corona::screenPool() const { return m_screenPool; } UniversalSettings *Corona::universalSettings() const { return m_universalSettings; } LayoutManager *Corona::layoutManager() const { return m_layoutManager; } AbstractWindowInterface *Corona::wm() const { return m_wm; } PlasmaThemeExtended *Corona::themeExtended() const { return m_themeExtended; } int Corona::numScreens() const { return qGuiApp->screens().count(); } QRect Corona::screenGeometry(int id) const { const auto screens = qGuiApp->screens(); const QScreen *screen{qGuiApp->primaryScreen()}; QString screenName; if (m_screenPool->knownIds().contains(id)) screenName = m_screenPool->connector(id); foreach (auto scr, screens) { if (scr->name() == screenName) { screen = scr; break; } } return screen->geometry(); } QRegion Corona::availableScreenRegion(int id) const { return availableScreenRegionWithCriteria(id); } QRegion Corona::availableScreenRegionWithCriteria(int id, QString forLayout) const { const auto screens = qGuiApp->screens(); const QScreen *screen{qGuiApp->primaryScreen()}; QString screenName; if (m_screenPool->knownIds().contains(id)) screenName = m_screenPool->connector(id); foreach (auto scr, screens) { if (scr->name() == screenName) { screen = scr; break; } } if (!screen) return QRegion(); QHash *views; if (forLayout.isEmpty()) { views = m_layoutManager->currentLatteViews(); } else { views = m_layoutManager->layoutLatteViews(forLayout); } QRegion available(screen->geometry()); if (views) { for (const auto *view : *views) { if (view && view->containment() && view->screen() == screen - && view->visibility() && (view->visibility()->mode() != Latte::Dock::AutoHide)) { + && view->visibility() && (view->visibility()->mode() != Latte::Types::AutoHide)) { int realThickness = view->normalThickness() - view->effects()->innerShadow(); // Usually availableScreenRect is used by the desktop, // but Latte don't have desktop, then here just // need calculate available space for top and bottom location, // because the left and right are those who dodge others views switch (view->location()) { case Plasma::Types::TopEdge: if (view->behaveAsPlasmaPanel()) { available -= view->geometry(); } else { QRect realGeometry; int realWidth = view->maxLength() * view->width(); switch (view->alignment()) { - case Latte::Dock::Left: + case Latte::Types::Left: realGeometry = QRect(view->x(), view->y(), realWidth, realThickness); break; - case Latte::Dock::Center: - case Latte::Dock::Justify: + case Latte::Types::Center: + case Latte::Types::Justify: realGeometry = QRect(qMax(view->geometry().x(), view->geometry().center().x() - realWidth / 2), view->y(), realWidth, realThickness); break; - case Latte::Dock::Right: + case Latte::Types::Right: realGeometry = QRect(view->geometry().right() - realWidth + 1, view->y(), realWidth, realThickness); break; } available -= realGeometry; } break; case Plasma::Types::BottomEdge: if (view->behaveAsPlasmaPanel()) { available -= view->geometry(); } else { QRect realGeometry; int realWidth = view->maxLength() * view->width(); int realY = view->geometry().bottom() - realThickness + 1; switch (view->alignment()) { - case Latte::Dock::Left: + case Latte::Types::Left: realGeometry = QRect(view->x(), realY, realWidth, realThickness); break; - case Latte::Dock::Center: - case Latte::Dock::Justify: + case Latte::Types::Center: + case Latte::Types::Justify: realGeometry = QRect(qMax(view->geometry().x(), view->geometry().center().x() - realWidth / 2), realY, realWidth, realThickness); break; - case Latte::Dock::Right: + case Latte::Types::Right: realGeometry = QRect(view->geometry().right() - realWidth + 1, realY, realWidth, realThickness); break; } available -= realGeometry; } break; default: //! bypass clang warnings break; } } } } /*qDebug() << "::::: FREE AREAS :::::"; for (int i = 0; i < available.rectCount(); ++i) { qDebug() << available.rects().at(i); } qDebug() << "::::: END OF FREE AREAS :::::";*/ return available; } QRect Corona::availableScreenRect(int id) const { return availableScreenRectWithCriteria(id); } -QRect Corona::availableScreenRectWithCriteria(int id, QList modes, QList edges) const +QRect Corona::availableScreenRectWithCriteria(int id, QList modes, QList edges) const { const auto screens = qGuiApp->screens(); const QScreen *screen{qGuiApp->primaryScreen()}; if (m_screenPool->knownIds().contains(id)) { QString scrName = m_screenPool->connector(id); foreach (auto scr, screens) { if (scr->name() == scrName) { screen = scr; break; } } } if (!screen) return {}; bool allModes = modes.isEmpty(); bool allEdges = edges.isEmpty(); auto available = screen->geometry(); QHash *views = m_layoutManager->currentLatteViews(); if (views) { for (const auto *view : *views) { if (view && view->containment() && view->screen() == screen && ((allEdges || edges.contains(view->location())) && (allModes || (view->visibility() && modes.contains(view->visibility()->mode()))))) { auto dockRect = view->absGeometry(); // Usually availableScreenRect is used by the desktop, // but Latte don't have desktop, then here just // need calculate available space for top and bottom location, // because the left and right are those who dodge others docks switch (view->location()) { case Plasma::Types::TopEdge: available.setTop(dockRect.bottom() + 1); break; case Plasma::Types::BottomEdge: available.setBottom(dockRect.top() - 1); break; case Plasma::Types::LeftEdge: available.setLeft(dockRect.right() + 1); break; case Plasma::Types::RightEdge: available.setRight(dockRect.left() - 1); break; default: //! bypass clang warnings break; } } } } return available; } void Corona::addOutput(QScreen *screen) { Q_ASSERT(screen); int id = m_screenPool->id(screen->name()); if (id == -1) { int newId = m_screenPool->firstAvailableId(); m_screenPool->insertScreenMapping(newId, screen->name()); } connect(screen, &QScreen::geometryChanged, this, [ = ]() { const int id = m_screenPool->id(screen->name()); if (id >= 0) { emit screenGeometryChanged(id); emit availableScreenRegionChanged(); emit availableScreenRectChanged(); } }); emit availableScreenRectChanged(); emit screenAdded(m_screenPool->id(screen->name())); } void Corona::primaryOutputChanged() { m_viewsScreenSyncTimer.start(); } void Corona::screenRemoved(QScreen *screen) { Q_ASSERT(screen); } void Corona::screenCountChanged() { m_viewsScreenSyncTimer.start(); } //! the central functions that updates loading/unloading latteviews //! concerning screen changed (for multi-screen setups mainly) void Corona::syncLatteViewsToScreens() { m_layoutManager->syncLatteViewsToScreens(); } int Corona::primaryScreenId() const { return m_screenPool->id(qGuiApp->primaryScreen()->name()); } void Corona::closeApplication() { //! this code must be called asynchronously because it is called //! also from qml (Settings window). QTimer::singleShot(5, [this]() { m_layoutManager->hideLatteSettingsDialog(); m_layoutManager->hideAllViews(); }); //! give the time for the views to hide themselves QTimer::singleShot(500, [this]() { qGuiApp->quit(); }); } void Corona::aboutApplication() { if (aboutDialog) { aboutDialog->hide(); aboutDialog->deleteLater(); } aboutDialog = new KAboutApplicationDialog(KAboutData::applicationData()); connect(aboutDialog.data(), &QDialog::finished, aboutDialog.data(), &QObject::deleteLater); m_wm->skipTaskBar(*aboutDialog); m_wm->setKeepAbove(*aboutDialog, true); aboutDialog->show(); } int Corona::screenForContainment(const Plasma::Containment *containment) const { //FIXME: indexOf is not a proper way to support multi-screen // as for environment to environment the indexes change // also there is the following issue triggered // from latteView adaptToScreen() // // in a multi-screen environment that // primary screen is not set to 0 it was // created an endless showing loop at // startup (catch-up race) between // screen:0 and primaryScreen //case in which this containment is child of an applet, hello systray :) if (Plasma::Applet *parentApplet = qobject_cast(containment->parent())) { if (Plasma::Containment *cont = parentApplet->containment()) { return screenForContainment(cont); } else { return -1; } } QHash *views = m_layoutManager->currentLatteViews(); //if the panel views already exist, base upon them Latte::View *view = views ? views->value(containment) : nullptr; if (view && view->screen()) { return m_screenPool->id(view->screen()->name()); } //Failed? fallback on lastScreen() //lastScreen() is the correct screen for panels //It is also correct for desktops *that have the correct activity()* //a containment with lastScreen() == 0 but another activity, //won't be associated to a screen // qDebug() << "ShellCorona screenForContainment: " << containment << " Last screen is " << containment->lastScreen(); for (auto screen : qGuiApp->screens()) { // containment->lastScreen() == m_screenPool->id(screen->name()) to check if the lastScreen refers to a screen that exists/it's known if (containment->lastScreen() == m_screenPool->id(screen->name()) && (containment->activity() == m_activityConsumer->currentActivity() || containment->containmentType() == Plasma::Types::PanelContainment || containment->containmentType() == Plasma::Types::CustomPanelContainment)) { return containment->lastScreen(); } } return -1; } void Corona::showAlternativesForApplet(Plasma::Applet *applet) { const QString alternativesQML = kPackage().filePath("appletalternativesui"); if (alternativesQML.isEmpty()) { return; } QHash *views = m_layoutManager->currentLatteViews(); Latte::View *latteView = (*views)[applet->containment()]; KDeclarative::QmlObject *qmlObj{nullptr}; if (latteView) { latteView->setAlternativesIsShown(true); qmlObj = new KDeclarative::QmlObject(latteView); } else { qmlObj = new KDeclarative::QmlObject(this); } qmlObj->setInitializationDelayed(true); qmlObj->setSource(QUrl::fromLocalFile(alternativesQML)); AlternativesHelper *helper = new AlternativesHelper(applet, qmlObj); qmlObj->rootContext()->setContextProperty(QStringLiteral("alternativesHelper"), helper); m_alternativesObjects << qmlObj; qmlObj->completeInitialization(); //! Alternative dialog signals connect(helper, &QObject::destroyed, this, [latteView]() { latteView->setAlternativesIsShown(false); }); connect(qmlObj->rootObject(), SIGNAL(visibleChanged(bool)), this, SLOT(alternativesVisibilityChanged(bool))); connect(applet, &Plasma::Applet::destroyedChanged, this, [this, qmlObj](bool destroyed) { if (!destroyed) { return; } QMutableListIterator it(m_alternativesObjects); while (it.hasNext()) { KDeclarative::QmlObject *obj = it.next(); if (obj == qmlObj) { it.remove(); obj->deleteLater(); } } }); } void Corona::alternativesVisibilityChanged(bool visible) { if (visible) { return; } QObject *root = sender(); QMutableListIterator it(m_alternativesObjects); while (it.hasNext()) { KDeclarative::QmlObject *obj = it.next(); if (obj->rootObject() == root) { it.remove(); obj->deleteLater(); } } } void Corona::loadDefaultLayout() { qDebug() << "loading default layout"; //! Settting mutable for create a containment setImmutability(Plasma::Types::Mutable); QVariantList args; auto defaultContainment = createContainmentDelayed("org.kde.latte.containment", args); defaultContainment->setContainmentType(Plasma::Types::PanelContainment); defaultContainment->init(); if (!defaultContainment || !defaultContainment->kPackage().isValid()) { qWarning() << "the requested containment plugin can not be located or loaded"; return; } auto config = defaultContainment->config(); defaultContainment->restore(config); using Plasma::Types; QList edges{Types::BottomEdge, Types::LeftEdge, Types::TopEdge, Types::RightEdge}; Layout *currentLayout = m_layoutManager->activeLayout(m_layoutManager->currentLayoutName()); if (currentLayout) { edges = currentLayout->freeEdges(defaultContainment->screen()); } if ((edges.count() > 0)) { defaultContainment->setLocation(edges.at(0)); } else { defaultContainment->setLocation(Plasma::Types::BottomEdge); } - if (m_layoutManager->memoryUsage() == Dock::MultipleLayouts) { + if (m_layoutManager->memoryUsage() == Latte::Types::MultipleLayouts) { config.writeEntry("layoutId", m_layoutManager->currentLayoutName()); } defaultContainment->updateConstraints(Plasma::Types::StartupCompletedConstraint); defaultContainment->save(config); requestConfigSync(); defaultContainment->flushPendingConstraintsEvents(); emit containmentAdded(defaultContainment); emit containmentCreated(defaultContainment); defaultContainment->createApplet(QStringLiteral("org.kde.latte.plasmoid")); defaultContainment->createApplet(QStringLiteral("org.kde.plasma.analogclock")); } QStringList Corona::containmentsIds() { QStringList ids; foreach (auto containment, containments()) { ids << QString::number(containment->id()); } return ids; } QStringList Corona::appletsIds() { QStringList ids; foreach (auto containment, containments()) { auto applets = containment->config().group("Applets"); ids << applets.groupList(); } return ids; } //! Activate launcher menu through dbus interface void Corona::activateLauncherMenu() { m_globalShortcuts->activateLauncherMenu(); } void Corona::windowColorScheme(QString windowIdAndScheme) { int firstSlash = windowIdAndScheme.indexOf("-"); QString windowIdStr = windowIdAndScheme.mid(0, firstSlash); QString schemeStr = windowIdAndScheme.mid(firstSlash + 1); m_wm->setColorSchemeForWindow(windowIdStr, schemeStr); } //! update badge for specific view item void Corona::updateDockItemBadge(QString identifier, QString value) { m_globalShortcuts->updateDockItemBadge(identifier, value); } void Corona::switchToLayout(QString layout) { m_layoutManager->switchToLayout(layout); } void Corona::showSettingsWindow(int page) { - Dock::LatteConfigPage p = Dock::LayoutPage; + Types::LatteConfigPage p = Types::LayoutPage; - if (page >= Dock::LayoutPage && page <= Dock::PreferencesPage) { - p = static_cast(page); + if (page >= Types::LayoutPage && page <= Types::PreferencesPage) { + p = static_cast(page); } m_layoutManager->showLatteSettingsDialog(p); } QStringList Corona::contextMenuData() { QStringList data; data << QString::number((int)m_layoutManager->memoryUsage()); data << m_layoutManager->currentLayoutName(); foreach (auto layoutName, m_layoutManager->menuLayouts()) { if (m_layoutManager->activeLayout(layoutName)) { data << QString("1," + layoutName); } else { data << QString("0," + layoutName); } } return data; } inline void Corona::qmlRegisterTypes() const { qmlRegisterType(); } } diff --git a/app/lattecorona.h b/app/lattecorona.h index 45aaa2fd..9e7021f9 100644 --- a/app/lattecorona.h +++ b/app/lattecorona.h @@ -1,188 +1,188 @@ /* * 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 . */ #ifndef LATTECORONA_H #define LATTECORONA_H // local -#include "../liblattedock/dock.h" +#include "../liblatte2/types.h" // Qt #include #include // Plasma #include // KDE #include namespace KDeclarative { class QmlObject; } namespace Plasma { class Corona; class Containment; class Types; } namespace PlasmaQuick { class ConfigView; } namespace KActivities { class Consumer; } namespace KWayland { namespace Client { class PlasmaShell; } } namespace Latte { class AbstractWindowInterface; class ScreenPool; class GlobalShortcuts; class UniversalSettings; class LayoutManager; class LaunchersSignals; class PlasmaThemeExtended; } namespace Latte { class Corona : public Plasma::Corona { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.kde.LatteDock") public: Corona(bool defaultLayoutOnStartup = false, QString layoutNameOnStartUp = QString(), int userSetMemoryUsage = -1, QObject *parent = nullptr); virtual ~Corona(); int numScreens() const override; QRect screenGeometry(int id) const override; QRegion availableScreenRegion(int id) const override; QRect availableScreenRect(int id) const override; //! This is a very generic function in order to return the availableScreenRect of specific screen //! by calculating only the user specified visibility modes and edges. Empty QLists for both //! arguments mean that all choices are accepted in calculations QRect availableScreenRectWithCriteria(int id, - QList modes = QList(), + QList modes = QList(), QList edges = QList()) const; QRegion availableScreenRegionWithCriteria(int id, QString forLayout = QString()) const; int screenForContainment(const Plasma::Containment *containment) const override; void closeApplication(); AbstractWindowInterface *wm() const; KActivities::Consumer *activitiesConsumer() const; ScreenPool *screenPool() const; UniversalSettings *universalSettings() const; LayoutManager *layoutManager() const; PlasmaThemeExtended *themeExtended() const; KWayland::Client::PlasmaShell *waylandCoronaInterface() const; //! these functions are used from context menu through containmentactions void switchToLayout(QString layout); void showSettingsWindow(int page); QStringList contextMenuData(); public slots: void aboutApplication(); void activateLauncherMenu(); //! they are separated with a "-" character void windowColorScheme(QString windowIdAndScheme); void loadDefaultLayout() override; void updateDockItemBadge(QString identifier, QString value); void unload(); signals: void configurationShown(PlasmaQuick::ConfigView *configView); void viewLocationChanged(); void raiseViewsTemporaryChanged(); private slots: void alternativesVisibilityChanged(bool visible); void showAlternativesForApplet(Plasma::Applet *applet); void load(); void addOutput(QScreen *screen); void primaryOutputChanged(); void screenRemoved(QScreen *screen); void screenCountChanged(); void syncLatteViewsToScreens(); private: void cleanConfig(); void qmlRegisterTypes() const; void setupWaylandIntegration(); bool appletExists(uint containmentId, uint appletId) const; bool containmentExists(uint id) const; int primaryScreenId() const; QStringList containmentsIds(); QStringList appletsIds(); bool m_activitiesStarting{true}; bool m_defaultLayoutOnStartup{false}; //! this is used to enforce loading the default layout on startup bool m_quitTimedEnded{false}; //! this is used on destructor in order to delay it and slide-out the views //!it can be used on startup to change memory usage from command line int m_userSetMemoryUsage{ -1}; QString m_layoutNameOnStartUp; QList m_alternativesObjects; QTimer m_viewsScreenSyncTimer; KActivities::Consumer *m_activityConsumer; QPointer aboutDialog; AbstractWindowInterface *m_wm{nullptr}; ScreenPool *m_screenPool{nullptr}; GlobalShortcuts *m_globalShortcuts{nullptr}; UniversalSettings *m_universalSettings{nullptr}; LayoutManager *m_layoutManager{nullptr}; PlasmaThemeExtended *m_themeExtended{nullptr}; KWayland::Client::PlasmaShell *m_waylandCorona{nullptr}; friend class GlobalShortcuts; friend class Layout; friend class LayoutManager; friend class LaunchersSignals; }; } #endif // LATTECORONA_H diff --git a/app/launcherssignals.cpp b/app/launcherssignals.cpp index d31eea6b..46bf6105 100644 --- a/app/launcherssignals.cpp +++ b/app/launcherssignals.cpp @@ -1,314 +1,314 @@ /* * 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 "launcherssignals.h" // local #include "lattecorona.h" #include "layout.h" // Qt #include // Plasma #include #include namespace Latte { LaunchersSignals::LaunchersSignals(QObject *parent) : QObject(parent) { m_manager = qobject_cast(parent); } LaunchersSignals::~LaunchersSignals() { } QList LaunchersSignals::lattePlasmoids(QString layoutName) { QList applets; Layout *layout = m_manager->activeLayout(layoutName); QList containments; if (layoutName.isEmpty()) { containments = m_manager->corona()->containments(); } else if (layout) { containments = *(layout->containments()); } foreach (auto containment, containments) { for (auto *applet : containment->applets()) { KPluginMetaData meta = applet->kPackage().metadata(); if (meta.pluginId() == "org.kde.latte.plasmoid") { applets.append(applet); } } } return applets; } void LaunchersSignals::addLauncher(QString layoutName, int launcherGroup, QString launcher) { - Dock::LaunchersGroup group = static_cast(launcherGroup); + Types::LaunchersGroup group = static_cast(launcherGroup); - if ((Dock::LaunchersGroup)group == Dock::UniqueLaunchers) { + if ((Types::LaunchersGroup)group == Types::UniqueLaunchers) { return; } - QString lName = (group == Dock::LayoutLaunchers) ? layoutName : ""; + QString lName = (group == Types::LayoutLaunchers) ? layoutName : ""; foreach (auto applet, lattePlasmoids(lName)) { 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()) { int methodIndex = metaObject->indexOfMethod("extSignalAddLauncher(QVariant,QVariant)"); if (methodIndex == -1) { continue; } QMetaMethod method = metaObject->method(methodIndex); method.invoke(item, Q_ARG(QVariant, launcherGroup), Q_ARG(QVariant, launcher)); } } } } } void LaunchersSignals::removeLauncher(QString layoutName, int launcherGroup, QString launcher) { - Dock::LaunchersGroup group = static_cast(launcherGroup); + Types::LaunchersGroup group = static_cast(launcherGroup); - if ((Dock::LaunchersGroup)group == Dock::UniqueLaunchers) { + if ((Types::LaunchersGroup)group == Types::UniqueLaunchers) { return; } - QString lName = (group == Dock::LayoutLaunchers) ? layoutName : ""; + QString lName = (group == Types::LayoutLaunchers) ? layoutName : ""; foreach (auto applet, lattePlasmoids(lName)) { 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()) { int methodIndex = metaObject->indexOfMethod("extSignalRemoveLauncher(QVariant,QVariant)"); if (methodIndex == -1) { continue; } QMetaMethod method = metaObject->method(methodIndex); method.invoke(item, Q_ARG(QVariant, launcherGroup), Q_ARG(QVariant, launcher)); } } } } } void LaunchersSignals::addLauncherToActivity(QString layoutName, int launcherGroup, QString launcher, QString activity) { - Dock::LaunchersGroup group = static_cast(launcherGroup); + Types::LaunchersGroup group = static_cast(launcherGroup); - if ((Dock::LaunchersGroup)group == Dock::UniqueLaunchers) { + if ((Types::LaunchersGroup)group == Types::UniqueLaunchers) { return; } - QString lName = (group == Dock::LayoutLaunchers) ? layoutName : ""; + QString lName = (group == Types::LayoutLaunchers) ? layoutName : ""; foreach (auto applet, lattePlasmoids(lName)) { 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()) { int methodIndex = metaObject->indexOfMethod("extSignalAddLauncherToActivity(QVariant,QVariant,QVariant)"); if (methodIndex == -1) { continue; } QMetaMethod method = metaObject->method(methodIndex); method.invoke(item, Q_ARG(QVariant, launcherGroup), Q_ARG(QVariant, launcher), Q_ARG(QVariant, activity)); } } } } } void LaunchersSignals::removeLauncherFromActivity(QString layoutName, int launcherGroup, QString launcher, QString activity) { - Dock::LaunchersGroup group = static_cast(launcherGroup); + Types::LaunchersGroup group = static_cast(launcherGroup); - if ((Dock::LaunchersGroup)group == Dock::UniqueLaunchers) { + if ((Types::LaunchersGroup)group == Types::UniqueLaunchers) { return; } - QString lName = (group == Dock::LayoutLaunchers) ? layoutName : ""; + QString lName = (group == Types::LayoutLaunchers) ? layoutName : ""; foreach (auto applet, lattePlasmoids(lName)) { 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()) { int methodIndex = metaObject->indexOfMethod("extSignalRemoveLauncherFromActivity(QVariant,QVariant,QVariant)"); if (methodIndex == -1) { continue; } QMetaMethod method = metaObject->method(methodIndex); method.invoke(item, Q_ARG(QVariant, launcherGroup), Q_ARG(QVariant, launcher), Q_ARG(QVariant, activity)); } } } } } void LaunchersSignals::urlsDropped(QString layoutName, int launcherGroup, QStringList urls) { - Dock::LaunchersGroup group = static_cast(launcherGroup); + Types::LaunchersGroup group = static_cast(launcherGroup); - if ((Dock::LaunchersGroup)group == Dock::UniqueLaunchers) { + if ((Types::LaunchersGroup)group == Types::UniqueLaunchers) { return; } - QString lName = (group == Dock::LayoutLaunchers) ? layoutName : ""; + QString lName = (group == Types::LayoutLaunchers) ? layoutName : ""; foreach (auto applet, lattePlasmoids(lName)) { 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()) { int methodIndex = metaObject->indexOfMethod("extSignalUrlsDropped(QVariant,QVariant)"); if (methodIndex == -1) { continue; } QMetaMethod method = metaObject->method(methodIndex); method.invoke(item, Q_ARG(QVariant, launcherGroup), Q_ARG(QVariant, urls)); } } } } } void LaunchersSignals::moveTask(QString layoutName, int senderId, int launcherGroup, int from, int to) { - Dock::LaunchersGroup group = static_cast(launcherGroup); + Types::LaunchersGroup group = static_cast(launcherGroup); - if ((Dock::LaunchersGroup)group == Dock::UniqueLaunchers) { + if ((Types::LaunchersGroup)group == Types::UniqueLaunchers) { return; } - QString lName = (group == Dock::LayoutLaunchers) ? layoutName : ""; + QString lName = (group == Types::LayoutLaunchers) ? layoutName : ""; foreach (auto applet, lattePlasmoids(lName)) { if (applet->id() != senderId) { 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()) { int methodIndex = metaObject->indexOfMethod("extSignalMoveTask(QVariant,QVariant,QVariant)"); if (methodIndex == -1) { continue; } QMetaMethod method = metaObject->method(methodIndex); method.invoke(item, Q_ARG(QVariant, launcherGroup), Q_ARG(QVariant, from), Q_ARG(QVariant, to)); } } } } } } void LaunchersSignals::validateLaunchersOrder(QString layoutName, int senderId, int launcherGroup, QStringList launchers) { - Dock::LaunchersGroup group = static_cast(launcherGroup); + Types::LaunchersGroup group = static_cast(launcherGroup); - if ((Dock::LaunchersGroup)group == Dock::UniqueLaunchers) { + if ((Types::LaunchersGroup)group == Types::UniqueLaunchers) { return; } - QString lName = (group == Dock::LayoutLaunchers) ? layoutName : ""; + QString lName = (group == Types::LayoutLaunchers) ? layoutName : ""; foreach (auto applet, lattePlasmoids(lName)) { if (applet->id() != senderId) { 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()) { int methodIndex = metaObject->indexOfMethod("extSignalValidateLaunchersOrder(QVariant,QVariant)"); if (methodIndex == -1) { continue; } QMetaMethod method = metaObject->method(methodIndex); method.invoke(item, Q_ARG(QVariant, launcherGroup), Q_ARG(QVariant, launchers)); } } } } } } } //end of namespace diff --git a/app/launcherssignals.h b/app/launcherssignals.h index ad84365e..d4ef4045 100644 --- a/app/launcherssignals.h +++ b/app/launcherssignals.h @@ -1,74 +1,74 @@ /* * 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 LAUNCHERSSIGNALS_H #define LAUNCHERSSIGNALS_H // local #include "layoutmanager.h" -#include "../liblattedock/dock.h" +#include "../liblatte2/types.h" // Qt #include namespace Plasma { class Applet; } namespace Latte { class LayoutManager; } namespace Latte { //! in order to support property the launcher groups Layout and Global //! the latte plasmoids must communicate between them with signals when //! there are changes in their models. This way we are trying to avoid //! crashes that occur by setting the launcherList of the tasksModel so //! often. The plasma devs of libtaskmanager have designed the launchers //! model to be initialized only once during startup class LaunchersSignals : public QObject { Q_OBJECT public: LaunchersSignals(QObject *parent); ~LaunchersSignals() override; public slots: Q_INVOKABLE void addLauncher(QString layoutName, int launcherGroup, QString launcher); Q_INVOKABLE void removeLauncher(QString layoutName, int launcherGroup, QString launcher); Q_INVOKABLE void addLauncherToActivity(QString layoutName, int launcherGroup, QString launcher, QString activity); Q_INVOKABLE void removeLauncherFromActivity(QString layoutName, int launcherGroup, QString launcher, QString activity); Q_INVOKABLE void urlsDropped(QString layoutName, int launcherGroup, QStringList urls); //!Deprecated because it could create crashes, validateLaunchersOrder provides a better approach Q_INVOKABLE void moveTask(QString layoutName, int senderId, int launcherGroup, int from, int to); Q_INVOKABLE void validateLaunchersOrder(QString layoutName, int senderId, int launcherGroup, QStringList launchers); private: QList lattePlasmoids(QString layoutName); private: LayoutManager *m_manager{nullptr}; }; } #endif diff --git a/app/layout.cpp b/app/layout.cpp index 64512d71..96de5767 100644 --- a/app/layout.cpp +++ b/app/layout.cpp @@ -1,1884 +1,1884 @@ /* * 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 "layout.h" // local #include "importer.h" #include "lattecorona.h" #include "layoutmanager.h" #include "screenpool.h" #include "view/positioner.h" #include "view/view.h" #include "settings/universalsettings.h" // Qt #include #include #include // KDE #include #include // Plasma #include #include #include namespace Latte { const QString Layout::MultipleLayoutsName = ".multiple-layouts_hidden"; Layout::Layout(QObject *parent, QString layoutFile, QString assignedName) : QObject(parent) { qDebug() << "Layout file to create object: " << layoutFile << " with name: " << assignedName; if (QFile(layoutFile).exists()) { if (assignedName.isEmpty()) { assignedName = layoutName(layoutFile); } //!this order is important because setFile initializes also the m_layoutGroup setFile(layoutFile); setName(assignedName); loadConfig(); init(); } } Layout::~Layout() { if (!m_layoutFile.isEmpty()) { m_layoutGroup.sync(); } } void Layout::syncToLayoutFile(bool removeLayoutId) { if (!m_corona || !isWritable()) { return; } KSharedConfigPtr filePtr = KSharedConfig::openConfig(m_layoutFile); KConfigGroup oldContainments = KConfigGroup(filePtr, "Containments"); oldContainments.deleteGroup(); oldContainments.sync(); qDebug() << " LAYOUT :: " << m_layoutName << " is syncing its original file."; foreach (auto containment, m_containments) { if (removeLayoutId) { containment->config().writeEntry("layoutId", ""); } KConfigGroup newGroup = oldContainments.group(QString::number(containment->id())); containment->config().copyTo(&newGroup); if (!removeLayoutId) { newGroup.writeEntry("layoutId", ""); newGroup.sync(); } } oldContainments.sync(); } void Layout::unloadContainments() { if (!m_corona) { return; } //!disconnect signals in order to avoid crashes when the layout is unloading disconnect(this, &Layout::viewsCountChanged, m_corona, &Plasma::Corona::availableScreenRectChanged); disconnect(this, &Layout::viewsCountChanged, m_corona, &Plasma::Corona::availableScreenRegionChanged); qDebug() << "Layout - " + name() + " unload: containments ... size ::: " << m_containments.size() << " ,latteViews in memory ::: " << m_latteViews.size() << " ,hidden latteViews in memory ::: " << m_waitingLatteViews.size(); foreach (auto view, m_latteViews) { view->disconnectSensitiveSignals(); } foreach (auto view, m_waitingLatteViews) { view->disconnectSensitiveSignals(); } m_unloadedContainmentsIds.clear(); QList systrays; //!identify systrays and unload them first foreach (auto containment, m_containments) { if (Plasma::Applet *parentApplet = qobject_cast(containment->parent())) { systrays.append(containment); } } while (!systrays.isEmpty()) { Plasma::Containment *systray = systrays.at(0); m_unloadedContainmentsIds << QString::number(systray->id()); systrays.removeFirst(); m_containments.removeAll(systray); delete systray; } while (!m_containments.isEmpty()) { Plasma::Containment *containment = m_containments.at(0); m_unloadedContainmentsIds << QString::number(containment->id()); m_containments.removeFirst(); delete containment; } } void Layout::unloadLatteViews() { if (!m_corona) { return; } qDebug() << "Layout - " + name() + " unload: latteViews ... size: " << m_latteViews.size(); qDeleteAll(m_latteViews); qDeleteAll(m_waitingLatteViews); m_latteViews.clear(); m_waitingLatteViews.clear(); } void Layout::init() { connect(this, &Layout::activitiesChanged, this, &Layout::saveConfig); connect(this, &Layout::backgroundChanged, this, &Layout::saveConfig); connect(this, &Layout::versionChanged, this, &Layout::saveConfig); connect(this, &Layout::colorChanged, this, &Layout::textColorChanged); connect(this, &Layout::disableBordersForMaximizedWindowsChanged, this, &Layout::saveConfig); connect(this, &Layout::showInMenuChanged, this, &Layout::saveConfig); connect(this, &Layout::textColorChanged, this, &Layout::saveConfig); connect(this, &Layout::launchersChanged, this, &Layout::saveConfig); connect(this, &Layout::lastUsedActivityChanged, this, &Layout::saveConfig); } void Layout::initToCorona(Latte::Corona *corona) { m_corona = corona; foreach (auto containment, m_corona->containments()) { - if (m_corona->layoutManager()->memoryUsage() == Dock::SingleLayout) { + if (m_corona->layoutManager()->memoryUsage() == Types::SingleLayout) { addContainment(containment); - } else if (m_corona->layoutManager()->memoryUsage() == Dock::MultipleLayouts) { + } else if (m_corona->layoutManager()->memoryUsage() == Types::MultipleLayouts) { QString layoutId = containment->config().readEntry("layoutId", QString()); if (!layoutId.isEmpty() && (layoutId == m_layoutName)) { addContainment(containment); } } } qDebug() << "Layout ::::: " << name() << " added contaiments ::: " << m_containments.size(); connect(m_corona->universalSettings(), &UniversalSettings::canDisableBordersChanged, this, [&]() { if (m_corona->universalSettings()->canDisableBorders()) { kwin_setDisabledMaximizedBorders(disableBordersForMaximizedWindows()); } else { kwin_setDisabledMaximizedBorders(false); } }); - if (m_corona->layoutManager()->memoryUsage() == Dock::SingleLayout && m_corona->universalSettings()->canDisableBorders()) { + if (m_corona->layoutManager()->memoryUsage() == Types::SingleLayout && m_corona->universalSettings()->canDisableBorders()) { kwin_setDisabledMaximizedBorders(disableBordersForMaximizedWindows()); - } else if (m_corona->layoutManager()->memoryUsage() == Dock::MultipleLayouts) { + } else if (m_corona->layoutManager()->memoryUsage() == Types::MultipleLayouts) { connect(m_corona->layoutManager(), &LayoutManager::currentLayoutNameChanged, this, [&]() { if (m_corona->universalSettings()->canDisableBorders() && m_corona->layoutManager()->currentLayoutName() == name()) { kwin_setDisabledMaximizedBorders(disableBordersForMaximizedWindows()); } }); } if (m_layoutName != MultipleLayoutsName) { updateLastUsedActivity(); } connect(m_corona, &Plasma::Corona::containmentAdded, this, &Layout::addContainment); connect(m_corona->m_activityConsumer, &KActivities::Consumer::currentActivityChanged, this, &Layout::updateLastUsedActivity); //!connect signals after adding the containment connect(this, &Layout::viewsCountChanged, m_corona, &Plasma::Corona::availableScreenRectChanged); connect(this, &Layout::viewsCountChanged, m_corona, &Plasma::Corona::availableScreenRegionChanged); emit viewsCountChanged(); } int Layout::version() const { return m_version; } void Layout::setVersion(int ver) { if (m_version == ver) { return; } m_version = ver; emit versionChanged(); } bool Layout::blockAutomaticLatteViewCreation() const { return m_blockAutomaticLatteViewCreation; } void Layout::setBlockAutomaticLatteViewCreation(bool block) { if (m_blockAutomaticLatteViewCreation == block) { return; } m_blockAutomaticLatteViewCreation = block; } bool Layout::disableBordersForMaximizedWindows() const { return m_disableBordersForMaximizedWindows; } void Layout::setDisableBordersForMaximizedWindows(bool disable) { if (m_disableBordersForMaximizedWindows == disable) { return; } m_disableBordersForMaximizedWindows = disable; kwin_setDisabledMaximizedBorders(disable); emit disableBordersForMaximizedWindowsChanged(); } bool Layout::kwin_disabledMaximizedBorders() const { //! Indentify Plasma Desktop version QProcess process; process.start("kreadconfig5 --file kwinrc --group Windows --key BorderlessMaximizedWindows"); process.waitForFinished(); QString output(process.readAllStandardOutput()); output = output.remove("\n"); return (output == "true"); } void Layout::kwin_setDisabledMaximizedBorders(bool disable) { if (kwin_disabledMaximizedBorders() == 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"); } } bool Layout::showInMenu() const { return m_showInMenu; } void Layout::setShowInMenu(bool show) { if (m_showInMenu == show) { return; } m_showInMenu = show; emit showInMenuChanged(); } bool Layout::isWritable() const { QFileInfo layoutFileInfo(m_layoutFile); if (layoutFileInfo.exists() && !layoutFileInfo.isWritable()) { return false; } else { return true; } } void Layout::lock() { QFileInfo layoutFileInfo(m_layoutFile); if (layoutFileInfo.exists() && layoutFileInfo.isWritable()) { QFile(m_layoutFile).setPermissions(QFileDevice::ReadUser | QFileDevice::ReadGroup | QFileDevice::ReadOther); } } void Layout::unlock() { QFileInfo layoutFileInfo(m_layoutFile); if (layoutFileInfo.exists() && !layoutFileInfo.isWritable()) { QFile(m_layoutFile).setPermissions(QFileDevice::ReadUser | QFileDevice::WriteUser | QFileDevice::ReadGroup | QFileDevice::ReadOther); } } QString Layout::background() const { return m_background; } void Layout::setBackground(QString path) { if (path == m_background) { return; } if (!path.isEmpty() && !QFileInfo(path).exists()) { return; } m_background = path; //! initialize the text color also if (path.isEmpty()) { setTextColor(QString()); } emit backgroundChanged(); } QString Layout::name() const { return m_layoutName; } void Layout::setName(QString name) { if (m_layoutName == name) { return; } qDebug() << "Layout name:" << name; m_layoutName = name; emit nameChanged(); } void Layout::renameLayout(QString newName) { if (m_layoutFile != Importer::layoutFilePath(newName)) { setFile(Importer::layoutFilePath(newName)); } if (m_layoutName != newName) { setName(newName); } //! thus this is a linked file if (m_corona) { foreach (auto containment, m_containments) { containment->config().writeEntry("layoutId", m_layoutName); } } } QString Layout::color() const { return m_color; } void Layout::setColor(QString color) { if (m_color == color) { return; } m_color = color; emit colorChanged(); } QString Layout::textColor() const { //! the user is in default layout theme if (m_background.isEmpty()) { if (m_color == "blue") { return "#D7E3FF"; } else if (m_color == "brown") { return "#F1DECB"; } else if (m_color == "darkgrey") { return "#ECECEC"; } else if (m_color == "gold") { return "#7C3636"; } else if (m_color == "green") { return "#4D7549"; } else if (m_color == "lightskyblue") { return "#0C2A43"; } else if (m_color == "orange") { return "#6F3902"; } else if (m_color == "pink") { return "#743C46"; } else if (m_color == "purple") { return "#ECD9FF"; } else if (m_color == "red") { return "#F3E4E4"; } else if (m_color == "wheat") { return "#6A4E25"; } else { return "#FCFCFC"; } } return "#" + m_textColor; } void Layout::setTextColor(QString color) { //! remove # if someone is trying to set it this way if (color.startsWith("#")) { color.remove(0, 1); } if (m_textColor == color) { return; } m_textColor = color; emit textColorChanged(); } QString Layout::file() const { return m_layoutFile; } void Layout::setFile(QString file) { if (m_layoutFile == file) { return; } qDebug() << "Layout file:" << file; m_layoutFile = file; KSharedConfigPtr filePtr = KSharedConfig::openConfig(m_layoutFile); m_layoutGroup = KConfigGroup(filePtr, "LayoutSettings"); emit fileChanged(); } QStringList Layout::launchers() const { return m_launchers; } void Layout::setLaunchers(QStringList launcherList) { if (m_launchers == launcherList) return; m_launchers = launcherList; emit launchersChanged(); } QStringList Layout::activities() const { return m_activities; } void Layout::setActivities(QStringList activities) { if (m_activities == activities) { return; } m_activities = activities; emit activitiesChanged(); } QStringList Layout::unloadedContainmentsIds() { return m_unloadedContainmentsIds; } bool Layout::isActiveLayout() const { if (!m_corona) { return false; } Layout *activeLayout = m_corona->layoutManager()->activeLayout(m_layoutName); if (activeLayout) { return true; } else { return false; } } bool Layout::isOriginalLayout() const { return m_layoutName != MultipleLayoutsName; } bool Layout::layoutIsBroken() const { if (m_layoutFile.isEmpty() || !QFile(m_layoutFile).exists()) { return false; } QStringList ids; QStringList conts; QStringList applets; KSharedConfigPtr lFile = KSharedConfig::openConfig(m_layoutFile); if (!m_corona) { KConfigGroup containmentsEntries = KConfigGroup(lFile, "Containments"); ids << containmentsEntries.groupList(); conts << ids; foreach (auto cId, containmentsEntries.groupList()) { auto appletsEntries = containmentsEntries.group(cId).group("Applets"); ids << appletsEntries.groupList(); applets << appletsEntries.groupList(); } } else { foreach (auto containment, m_containments) { ids << QString::number(containment->id()); conts << QString::number(containment->id()); foreach (auto applet, containment->applets()) { ids << QString::number(applet->id()); applets << QString::number(applet->id()); } } } QSet idsSet = QSet::fromList(ids); /* a different way to count duplicates QMap countOfStrings; for (int i = 0; i < ids.count(); i++) { countOfStrings[ids[i]]++; }*/ if (idsSet.count() != ids.count()) { qDebug() << " ---- ERROR - BROKEN LAYOUT :: " << m_layoutName << " ----"; if (!m_corona) { qDebug() << " --- file : " << m_layoutFile; } else { - if (m_corona->layoutManager()->memoryUsage() == Dock::MultipleLayouts) { + if (m_corona->layoutManager()->memoryUsage() == Types::MultipleLayouts) { qDebug() << " --- in multiple layouts hidden file : " << Importer::layoutFilePath(Layout::MultipleLayoutsName); } else { qDebug() << " --- in layout file : " << m_layoutFile; } } qDebug() << "Contaiments :: " << conts; qDebug() << "Applets :: " << applets; foreach (QString c, conts) { if (applets.contains(c)) { qDebug() << "Error: Same applet and containment id found ::: " << c; } } for (int i = 0; i < ids.count(); ++i) { for (int j = i + 1; j < ids.count(); ++j) { if (ids[i] == ids[j]) { qDebug() << "Error: Applets with same id ::: " << ids[i]; } } } qDebug() << " -- - -- - -- - -- - - -- - - - - -- - - - - "; if (!m_corona) { KConfigGroup containmentsEntries = KConfigGroup(lFile, "Containments"); foreach (auto cId, containmentsEntries.groupList()) { auto appletsEntries = containmentsEntries.group(cId).group("Applets"); qDebug() << " CONTAINMENT : " << cId << " APPLETS : " << appletsEntries.groupList(); } } else { foreach (auto containment, m_containments) { QStringList appletsIds; foreach (auto applet, containment->applets()) { appletsIds << QString::number(applet->id()); } qDebug() << " CONTAINMENT : " << containment->id() << " APPLETS : " << appletsIds.join(","); } } return true; } return false; } QString Layout::layoutName(const QString &fileName) { int lastSlash = fileName.lastIndexOf("/"); QString tempLayoutFile = fileName; QString layoutName = tempLayoutFile.remove(0, lastSlash + 1); int ext = layoutName.lastIndexOf(".layout.latte"); layoutName = layoutName.remove(ext, 13); return layoutName; } void Layout::loadConfig() { m_version = m_layoutGroup.readEntry("version", 2); m_color = m_layoutGroup.readEntry("color", QString("blue")); m_disableBordersForMaximizedWindows = m_layoutGroup.readEntry("disableBordersForMaximizedWindows", false); m_showInMenu = m_layoutGroup.readEntry("showInMenu", false); m_textColor = m_layoutGroup.readEntry("textColor", QString("fcfcfc")); m_activities = m_layoutGroup.readEntry("activities", QStringList()); m_launchers = m_layoutGroup.readEntry("launchers", QStringList()); m_lastUsedActivity = m_layoutGroup.readEntry("lastUsedActivity", QString()); QString back = m_layoutGroup.readEntry("background", ""); if (!back.isEmpty()) { if (QFileInfo(back).exists()) { m_background = back; } else { m_layoutGroup.writeEntry("background", QString()); } } emit activitiesChanged(); } void Layout::saveConfig() { qDebug() << "layout is saving... for layout:" << m_layoutName; m_layoutGroup.writeEntry("version", m_version); m_layoutGroup.writeEntry("showInMenu", m_showInMenu); m_layoutGroup.writeEntry("color", m_color); m_layoutGroup.writeEntry("disableBordersForMaximizedWindows", m_disableBordersForMaximizedWindows); m_layoutGroup.writeEntry("launchers", m_launchers); m_layoutGroup.writeEntry("background", m_background); m_layoutGroup.writeEntry("activities", m_activities); m_layoutGroup.writeEntry("lastUsedActivity", m_lastUsedActivity); m_layoutGroup.writeEntry("textColor", m_textColor); m_layoutGroup.sync(); } //! Containments Actions void Layout::addContainment(Plasma::Containment *containment) { if (!containment || m_containments.contains(containment)) { return; } bool containmentInLayout{false}; - if (m_corona->layoutManager()->memoryUsage() == Dock::SingleLayout) { + if (m_corona->layoutManager()->memoryUsage() == Types::SingleLayout) { m_containments.append(containment); containmentInLayout = true; - } else if (m_corona->layoutManager()->memoryUsage() == Dock::MultipleLayouts) { + } else if (m_corona->layoutManager()->memoryUsage() == Types::MultipleLayouts) { QString layoutId = containment->config().readEntry("layoutId", QString()); if (!layoutId.isEmpty() && (layoutId == m_layoutName)) { m_containments.append(containment); containmentInLayout = true; } } if (containmentInLayout) { if (!blockAutomaticLatteViewCreation()) { addView(containment); } else { qDebug() << "delaying LatteView creation for containment :: " << containment->id(); } connect(containment, &QObject::destroyed, this, &Layout::containmentDestroyed); } } QHash *Layout::latteViews() { return &m_latteViews; } QList *Layout::containments() { return &m_containments; } const QStringList Layout::appliedActivities() { if (!m_corona) { return {}; } - if (m_corona->layoutManager()->memoryUsage() == Dock::SingleLayout) { + if (m_corona->layoutManager()->memoryUsage() == Types::SingleLayout) { return {"0"}; - } else if (m_corona->layoutManager()->memoryUsage() == Dock::MultipleLayouts) { + } else if (m_corona->layoutManager()->memoryUsage() == Types::MultipleLayouts) { if (m_activities.isEmpty()) { return m_corona->layoutManager()->orphanedActivities(); } else { return m_activities; } } else { return {"0"}; } } QString Layout::lastUsedActivity() { return m_lastUsedActivity; } void Layout::clearLastUsedActivity() { m_lastUsedActivity = ""; emit lastUsedActivityChanged(); } void Layout::updateLastUsedActivity() { if (!m_corona) { return; } if (!m_lastUsedActivity.isEmpty() && !m_corona->layoutManager()->activities().contains(m_lastUsedActivity)) { clearLastUsedActivity(); } QString currentId = m_corona->activitiesConsumer()->currentActivity(); QStringList appliedActivitiesIds = appliedActivities(); if (m_lastUsedActivity != currentId && (appliedActivitiesIds.contains(currentId) - || m_corona->layoutManager()->memoryUsage() == Dock::SingleLayout)) { + || m_corona->layoutManager()->memoryUsage() == Types::SingleLayout)) { m_lastUsedActivity = currentId; emit lastUsedActivityChanged(); } } void Layout::destroyedChanged(bool destroyed) { if (!m_corona) { return; } qDebug() << "dock containment destroyed changed!!!!"; Plasma::Containment *sender = qobject_cast(QObject::sender()); if (!sender) { return; } if (destroyed) { m_waitingLatteViews[sender] = m_latteViews.take(static_cast(sender)); } else { m_latteViews[sender] = m_waitingLatteViews.take(static_cast(sender)); } emit viewsCountChanged(); } void Layout::containmentDestroyed(QObject *cont) { if (!m_corona) { return; } Plasma::Containment *containment = static_cast(cont); if (containment) { int containmentIndex = m_containments.indexOf(containment); if (containmentIndex >= 0) { m_containments.removeAt(containmentIndex); } qDebug() << "Layout " << name() << " :: containment destroyed!!!!"; auto view = m_latteViews.take(containment); if (!view) { view = m_waitingLatteViews.take(containment); } if (view) { view->disconnectSensitiveSignals(); view->deleteLater(); emit viewsCountChanged(); emit viewColorizerChanged(); } } } void Layout::addView(Plasma::Containment *containment, bool forceOnPrimary, int explicitScreen) { qDebug() << "Layout :::: " << m_layoutName << " ::: addView was called... m_containments :: " << m_containments.size(); if (!containment || !m_corona || !containment->kPackage().isValid()) { qWarning() << "the requested containment plugin can not be located or loaded"; return; } qDebug() << "step 1..."; if (!isLatteContainment(containment)) return; qDebug() << "step 2..."; for (auto *dock : m_latteViews) { if (dock->containment() == containment) return; } qDebug() << "step 3..."; QScreen *nextScreen{qGuiApp->primaryScreen()}; bool onPrimary = containment->config().readEntry("onPrimary", true); int id = containment->screen(); if (id == -1 && explicitScreen == -1) { id = containment->lastScreen(); } if (explicitScreen > -1) { id = explicitScreen; } qDebug() << "add dock - containment id: " << containment->id() << " ,screen : " << id << " - " << m_corona->screenPool()->connector(id) << " ,onprimary:" << onPrimary << " - " << qGuiApp->primaryScreen()->name() << " ,forceOnPrimary:" << forceOnPrimary; if (id >= 0 && !onPrimary && !forceOnPrimary) { QString connector = m_corona->screenPool()->connector(id); qDebug() << "add dock - connector : " << connector; bool found{false}; foreach (auto scr, qGuiApp->screens()) { if (scr && scr->name() == connector) { found = true; nextScreen = scr; break; } } if (!found) { qDebug() << "reject : adding explicit dock, screen not available ! : " << connector; return; } //! explicit dock can not be added at explicit screen when that screen is the same with //! primary screen and that edge is already occupied by a primary dock if (nextScreen == qGuiApp->primaryScreen() && primaryDockOccupyEdge(containment->location())) { qDebug() << "reject : adding explicit dock, primary dock occupies edge at screen ! : " << connector; return; } } if (id >= 0 && onPrimary) { QString connector = m_corona->screenPool()->connector(id); qDebug() << "add dock - connector : " << connector; foreach (auto view, m_latteViews) { auto testContainment = view->containment(); int testScreenId = testContainment->screen(); if (testScreenId == -1) { testScreenId = testContainment->lastScreen(); } bool testOnPrimary = testContainment->config().readEntry("onPrimary", true); Plasma::Types::Location testLocation = static_cast((int)testContainment->config().readEntry("location", (int)Plasma::Types::BottomEdge)); if (!testOnPrimary && m_corona->screenPool()->primaryScreenId() == testScreenId && testLocation == containment->location()) { qDebug() << "Rejected explicit latteView and removing it in order add an onPrimary with higher priority at screen: " << connector; auto viewToDelete = m_latteViews.take(testContainment); viewToDelete->disconnectSensitiveSignals(); viewToDelete->deleteLater(); } } } /* old behavior to not add primary docks on explicit one else if (onPrimary) { if (explicitDockOccupyEdge(m_corona->screenPool()->primaryScreenId(), containment->location())) { qDebug() << "CORONA ::: adding dock rejected, the edge is occupied by explicit dock ! : " << containment->location(); //we must check that an onPrimary dock should never catch up the same edge on //the same screen with an explicit dock return; } }*/ qDebug() << "Adding dock for container..."; qDebug() << "onPrimary: " << onPrimary << "screen!!! :" << nextScreen->name(); //! it is used to set the correct flag during the creation //! of the window... This of course is also used during //! recreations of the window between different visibility modes - auto mode = static_cast(containment->config().readEntry("visibility", static_cast(Dock::DodgeActive))); + auto mode = static_cast(containment->config().readEntry("visibility", static_cast(Types::DodgeActive))); bool byPassWM{false}; - if (mode == Dock::AlwaysVisible || mode == Dock::WindowsGoBelow) { + if (mode == Types::AlwaysVisible || mode == Types::WindowsGoBelow) { byPassWM = false; } else { byPassWM = containment->config().readEntry("byPassWM", false); } auto latteView = new Latte::View(m_corona, nextScreen, byPassWM); latteView->init(); latteView->setContainment(containment); latteView->setManagedLayout(this); //! force this special dock case to become primary //! even though it isnt if (forceOnPrimary) { qDebug() << "Enforcing onPrimary:true as requested for LatteView..."; latteView->setOnPrimary(true); } // connect(containment, &QObject::destroyed, this, &Layout::containmentDestroyed); connect(containment, &Plasma::Applet::destroyedChanged, this, &Layout::destroyedChanged); connect(containment, &Plasma::Applet::locationChanged, m_corona, &Latte::Corona::viewLocationChanged); connect(containment, &Plasma::Containment::appletAlternativesRequested , m_corona, &Latte::Corona::showAlternativesForApplet, Qt::QueuedConnection); - if (m_corona->layoutManager()->memoryUsage() == Dock::MultipleLayouts) { + if (m_corona->layoutManager()->memoryUsage() == Types::MultipleLayouts) { connect(containment, &Plasma::Containment::appletCreated, this, &Layout::appletCreated); } connect(latteView->effects(), &ViewPart::Effects::colorizerEnabledChanged, this, &Layout::viewColorizerChanged); //! Qt 5.9 creates a crash for this in wayland, that is why the check is used //! but on the other hand we need this for copy to work correctly and show //! the copied dock under X11 //if (!KWindowSystem::isPlatformWayland()) { latteView->show(); //} m_latteViews[containment] = latteView; emit viewColorizerChanged(); emit viewsCountChanged(); } void Layout::addNewView() { if (!m_corona) { return; } m_corona->loadDefaultLayout(); } void Layout::copyView(Plasma::Containment *containment) { if (!containment || !m_corona) return; qDebug() << "copying containment layout"; //! Settting mutable for create a containment m_corona->setImmutability(Plasma::Types::Mutable); QString temp1File = QDir::homePath() + "/.config/lattedock.copy1.bak"; //! WE NEED A WAY TO COPY A CONTAINMENT!!!! QFile copyFile(temp1File); if (copyFile.exists()) copyFile.remove(); KSharedConfigPtr newFile = KSharedConfig::openConfig(temp1File); KConfigGroup copied_conts = KConfigGroup(newFile, "Containments"); KConfigGroup copied_c1 = KConfigGroup(&copied_conts, QString::number(containment->id())); KConfigGroup copied_systray; // toCopyContainmentIds << QString::number(containment->id()); // toCopyAppletIds << containment->config().group("Applets").groupList(); containment->config().copyTo(&copied_c1); //!investigate if there is a systray in the containment to copy also int systrayId = -1; QString systrayAppletId; auto applets = containment->config().group("Applets"); foreach (auto applet, applets.groupList()) { KConfigGroup appletSettings = applets.group(applet).group("Configuration"); int tSysId = appletSettings.readEntry("SystrayContainmentId", -1); if (tSysId != -1) { systrayId = tSysId; systrayAppletId = applet; qDebug() << "systray was found in the containment... ::: " << tSysId; break; } } if (systrayId != -1) { Plasma::Containment *systray{nullptr}; foreach (auto containment, m_corona->containments()) { if (containment->id() == systrayId) { systray = containment; break; } } if (systray) { copied_systray = KConfigGroup(&copied_conts, QString::number(systray->id())); // toCopyContainmentIds << QString::number(systray->id()); // toCopyAppletIds << systray->config().group("Applets").groupList(); systray->config().copyTo(&copied_systray); } } //! end of systray specific code //! update ids to unique ones QString temp2File = newUniqueIdsLayoutFromFile(temp1File); //! Don't create LatteView when the containment is created because we must update //! its screen settings first setBlockAutomaticLatteViewCreation(true); //! Finally import the configuration QList importedDocks = importLayoutFile(temp2File); Plasma::Containment *newContainment{nullptr}; if (importedDocks.size() == 1) { newContainment = importedDocks[0]; } if (!newContainment || !newContainment->kPackage().isValid()) { qWarning() << "the requested containment plugin can not be located or loaded"; return; } auto config = newContainment->config(); //in multi-screen environment the copied dock is moved to alternative screens first const auto screens = qGuiApp->screens(); auto dock = m_latteViews[containment]; bool setOnExplicitScreen = false; int dockScrId = -1; int copyScrId = -1; if (dock) { dockScrId = dock->positioner()->currentScreenId(); qDebug() << "COPY DOCK SCREEN ::: " << dockScrId; if (dockScrId != -1 && screens.count() > 1) { foreach (auto scr, screens) { copyScrId = m_corona->screenPool()->id(scr->name()); //the screen must exist and not be the same with the original dock if (copyScrId > -1 && copyScrId != dockScrId) { QList fEdges = freeEdges(copyScrId); if (fEdges.contains((Plasma::Types::Location)containment->location())) { ///set this containment to an explicit screen config.writeEntry("onPrimary", false); config.writeEntry("lastScreen", copyScrId); newContainment->setLocation(containment->location()); qDebug() << "COPY DOCK SCREEN NEW SCREEN ::: " << copyScrId; setOnExplicitScreen = true; break; } } } } } if (!setOnExplicitScreen) { QList edges = freeEdges(newContainment->screen()); if (edges.count() > 0) { newContainment->setLocation(edges.at(0)); } else { newContainment->setLocation(Plasma::Types::BottomEdge); } config.writeEntry("onPrimary", false); config.writeEntry("lastScreen", dockScrId); } newContainment->config().sync(); if (setOnExplicitScreen && copyScrId > -1) { qDebug() << "Copy Dock in explicit screen ::: " << copyScrId; addView(newContainment, false, copyScrId); newContainment->reactToScreenChange(); } else { qDebug() << "Copy Dock in current screen..."; addView(newContainment, false, dockScrId); } setBlockAutomaticLatteViewCreation(false); } void Layout::appletCreated(Plasma::Applet *applet) { //! In Multiple Layout the orphaned systrays must be assigned to layouts //! when the user adds them KConfigGroup appletSettings = applet->containment()->config().group("Applets").group(QString::number(applet->id())).group("Configuration"); int systrayId = appletSettings.readEntry("SystrayContainmentId", -1); if (systrayId != -1) { uint sId = (uint)systrayId; foreach (auto containment, m_corona->containments()) { if (containment->id() == sId) { containment->config().writeEntry("layoutId", m_layoutName); } addContainment(containment); } } } void Layout::importToCorona() { if (!m_corona) { return; } //! Settting mutable for create a containment m_corona->setImmutability(Plasma::Types::Mutable); QString temp1FilePath = QDir::homePath() + "/.config/lattedock.copy1.bak"; //! we need to copy first the layout file because the kde cache //! may not have yet been updated (KSharedConfigPtr) //! this way we make sure at the latest changes stored in the layout file //! will be also available when changing to Myltiple Layouts QString tempLayoutFilePath = QDir::homePath() + "/.config/lattedock.layout.bak"; //! WE NEED A WAY TO COPY A CONTAINMENT!!!! QFile tempLayoutFile(tempLayoutFilePath); QFile copyFile(temp1FilePath); QFile layoutOriginalFile(m_layoutFile); if (tempLayoutFile.exists()) { tempLayoutFile.remove(); } if (copyFile.exists()) copyFile.remove(); layoutOriginalFile.copy(tempLayoutFilePath); KSharedConfigPtr filePtr = KSharedConfig::openConfig(tempLayoutFilePath); KSharedConfigPtr newFile = KSharedConfig::openConfig(temp1FilePath); KConfigGroup copyGroup = KConfigGroup(newFile, "Containments"); KConfigGroup current_containments = KConfigGroup(filePtr, "Containments"); current_containments.copyTo(©Group); copyGroup.sync(); //! update ids to unique ones QString temp2File = newUniqueIdsLayoutFromFile(temp1FilePath); //! Finally import the configuration importLayoutFile(temp2File); } QString Layout::availableId(QStringList all, QStringList assigned, int base) { bool found = false; int i = base; while (!found && i < 32000) { QString iStr = QString::number(i); if (!all.contains(iStr) && !assigned.contains(iStr)) { return iStr; } i++; } return QString(""); } QString Layout::newUniqueIdsLayoutFromFile(QString file) { if (!m_corona) { return QString(); } QString tempFile = QDir::homePath() + "/.config/lattedock.copy2.bak"; QFile copyFile(tempFile); if (copyFile.exists()) copyFile.remove(); //! BEGIN updating the ids in the temp file QStringList allIds; allIds << m_corona->containmentsIds(); allIds << m_corona->appletsIds(); QStringList toInvestigateContainmentIds; QStringList toInvestigateAppletIds; QStringList toInvestigateSystrayContIds; //! first is the systray containment id QHash systrayParentContainmentIds; QHash systrayAppletIds; //qDebug() << "Ids:" << allIds; //qDebug() << "to copy containments: " << toCopyContainmentIds; //qDebug() << "to copy applets: " << toCopyAppletIds; QStringList assignedIds; QHash assigned; KSharedConfigPtr filePtr = KSharedConfig::openConfig(file); KConfigGroup investigate_conts = KConfigGroup(filePtr, "Containments"); //KConfigGroup copied_c1 = KConfigGroup(&copied_conts, QString::number(containment->id())); //! Record the containment and applet ids foreach (auto cId, investigate_conts.groupList()) { toInvestigateContainmentIds << cId; auto appletsEntries = investigate_conts.group(cId).group("Applets"); toInvestigateAppletIds << appletsEntries.groupList(); //! investigate for systrays foreach (auto appletId, appletsEntries.groupList()) { KConfigGroup appletSettings = appletsEntries.group(appletId).group("Configuration"); int tSysId = appletSettings.readEntry("SystrayContainmentId", -1); //! It is a systray !!! if (tSysId != -1) { QString tSysIdStr = QString::number(tSysId); toInvestigateSystrayContIds << tSysIdStr; systrayParentContainmentIds[tSysIdStr] = cId; systrayAppletIds[tSysIdStr] = appletId; qDebug() << "systray was found in the containment..."; } } } //! Reassign containment and applet ids to unique ones foreach (auto contId, toInvestigateContainmentIds) { QString newId = availableId(allIds, assignedIds, 12); assignedIds << newId; assigned[contId] = newId; } foreach (auto appId, toInvestigateAppletIds) { QString newId = availableId(allIds, assignedIds, 40); assignedIds << newId; assigned[appId] = newId; } qDebug() << "ALL CORONA IDS ::: " << allIds; qDebug() << "FULL ASSIGNMENTS ::: " << assigned; foreach (auto cId, toInvestigateContainmentIds) { QString value = assigned[cId]; if (assigned.contains(value)) { QString value2 = assigned[value]; if (cId != assigned[cId] && !value2.isEmpty() && cId == value2) { qDebug() << "PROBLEM APPEARED !!!! FOR :::: " << cId << " .. fixed .."; assigned[cId] = cId; assigned[value] = value; } } } foreach (auto aId, toInvestigateAppletIds) { QString value = assigned[aId]; if (assigned.contains(value)) { QString value2 = assigned[value]; if (aId != assigned[aId] && !value2.isEmpty() && aId == value2) { qDebug() << "PROBLEM APPEARED !!!! FOR :::: " << aId << " .. fixed .."; assigned[aId] = aId; assigned[value] = value; } } } qDebug() << "FIXED FULL ASSIGNMENTS ::: " << assigned; //! update applet ids in their contaiment order and in MultipleLayouts update also the layoutId foreach (auto cId, investigate_conts.groupList()) { //! Update (appletOrder) and (lockedZoomApplets) for (int i = 1; i <= 2; ++i) { QString settingStr = (i == 1) ? "appletOrder" : "lockedZoomApplets"; QString order1 = investigate_conts.group(cId).group("General").readEntry(settingStr, QString()); if (!order1.isEmpty()) { QStringList order1Ids = order1.split(";"); QStringList fixedOrder1Ids; for (int i = 0; i < order1Ids.count(); ++i) { fixedOrder1Ids.append(assigned[order1Ids[i]]); } QString fixedOrder1 = fixedOrder1Ids.join(";"); investigate_conts.group(cId).group("General").writeEntry(settingStr, fixedOrder1); } } - if (m_corona->layoutManager()->memoryUsage() == Dock::MultipleLayouts) { + if (m_corona->layoutManager()->memoryUsage() == Types::MultipleLayouts) { investigate_conts.group(cId).writeEntry("layoutId", m_layoutName); } } //! must update also the systray id in its applet foreach (auto systrayId, toInvestigateSystrayContIds) { KConfigGroup systrayParentContainment = investigate_conts.group(systrayParentContainmentIds[systrayId]); systrayParentContainment.group("Applets").group(systrayAppletIds[systrayId]).group("Configuration").writeEntry("SystrayContainmentId", assigned[systrayId]); systrayParentContainment.sync(); } investigate_conts.sync(); //! Copy To Temp 2 File And Update Correctly The Ids KSharedConfigPtr file2Ptr = KSharedConfig::openConfig(tempFile); KConfigGroup fixedNewContainmets = KConfigGroup(file2Ptr, "Containments"); foreach (auto contId, investigate_conts.groupList()) { QString pluginId = investigate_conts.group(contId).readEntry("plugin", ""); if (pluginId != "org.kde.desktopcontainment") { //!don't add ghost containments KConfigGroup newContainmentGroup = fixedNewContainmets.group(assigned[contId]); investigate_conts.group(contId).copyTo(&newContainmentGroup); newContainmentGroup.group("Applets").deleteGroup(); foreach (auto appId, investigate_conts.group(contId).group("Applets").groupList()) { KConfigGroup appletGroup = investigate_conts.group(contId).group("Applets").group(appId); KConfigGroup newAppletGroup = fixedNewContainmets.group(assigned[contId]).group("Applets").group(assigned[appId]); appletGroup.copyTo(&newAppletGroup); } } } fixedNewContainmets.sync(); return tempFile; } QList Layout::importLayoutFile(QString file) { KSharedConfigPtr filePtr = KSharedConfig::openConfig(file); auto newContainments = m_corona->importLayout(KConfigGroup(filePtr, "")); ///Find latte and systray containments qDebug() << " imported containments ::: " << newContainments.length(); QList importedDocks; //QList systrays; foreach (auto containment, newContainments) { if (isLatteContainment(containment)) { qDebug() << "new latte containment id: " << containment->id(); importedDocks << containment; } } ///after systrays were found we must update in latte the relevant ids /*if (!systrays.isEmpty()) { foreach (auto systray, systrays) { qDebug() << "systray found with id : " << systray->id(); Plasma::Applet *parentApplet = qobject_cast(systray->parent()); if (parentApplet) { KConfigGroup appletSettings = parentApplet->config().group("Configuration"); if (appletSettings.hasKey("SystrayContainmentId")) { qDebug() << "!!! updating systray id to : " << systray->id(); appletSettings.writeEntry("SystrayContainmentId", systray->id()); } } } }*/ return importedDocks; } void Layout::recreateView(Plasma::Containment *containment) { if (!m_corona) { return; } //! give the time to config window to close itself first and then recreate the dock //! step:1 remove the latteview QTimer::singleShot(350, [this, containment]() { auto view = m_latteViews.take(containment); if (view) { qDebug() << "recreate - step 1: removing dock for containment:" << containment->id(); //! step:2 add the new latteview connect(view, &QObject::destroyed, this, [this, containment]() { QTimer::singleShot(250, this, [this, containment]() { if (!m_latteViews.contains(containment)) { qDebug() << "recreate - step 2: adding dock for containment:" << containment->id(); addView(containment); } }); }); view->deleteLater(); } }); } //! the central functions that updates loading/unloading latteviews //! concerning screen changed (for multi-screen setups mainly) void Layout::syncLatteViewsToScreens() { if (!m_corona) { return; } qDebug() << "start of, syncLatteViewsToScreens ...."; qDebug() << "LAYOUT ::: " << name(); qDebug() << "screen count changed -+-+ " << qGuiApp->screens().size(); QHash> futureDocksLocations; QList futureShownViews; QString prmScreenName = qGuiApp->primaryScreen()->name(); //! first step: primary docks must be placed in primary screen free edges foreach (auto containment, m_containments) { if (isLatteContainment(containment)) { int screenId = containment->screen(); if (screenId == -1) { screenId = containment->lastScreen(); } bool onPrimary = containment->config().readEntry("onPrimary", true); Plasma::Types::Location location = static_cast((int)containment->config().readEntry("location", (int)Plasma::Types::BottomEdge)); if (onPrimary && !futureDocksLocations[prmScreenName].contains(location)) { futureDocksLocations[prmScreenName].append(location); futureShownViews.append(containment->id()); } } } //! second step: explicit docks must be placed in their screens if the screen edge is free foreach (auto containment, m_containments) { if (isLatteContainment(containment)) { int screenId = containment->screen(); if (screenId == -1) { screenId = containment->lastScreen(); } bool onPrimary = containment->config().readEntry("onPrimary", true); Plasma::Types::Location location = static_cast((int)containment->config().readEntry("location", (int)Plasma::Types::BottomEdge)); if (!onPrimary) { QString expScreenName = m_corona->screenPool()->connector(screenId); if (m_corona->screenPool()->screenExists(screenId) && !futureDocksLocations[expScreenName].contains(location)) { futureDocksLocations[expScreenName].append(location); futureShownViews.append(containment->id()); } } } } qDebug() << "PRIMARY SCREEN :: " << prmScreenName; qDebug() << "LATTEVIEWS MUST BE PRESENT AT :: " << futureDocksLocations; qDebug() << "FUTURESHOWNVIEWS MUST BE :: " << futureShownViews; //! add views foreach (auto containment, m_containments) { int screenId = containment->screen(); if (screenId == -1) { screenId = containment->lastScreen(); } if (!latteViewExists(containment) && futureShownViews.contains(containment->id())) { qDebug() << "syncLatteViewsToScreens: view must be added... for containment:" << containment->id() << " at screen:" << m_corona->screenPool()->connector(screenId); addView(containment); } } //! remove views foreach (auto view, m_latteViews) { if (view->containment() && !futureShownViews.contains(view->containment()->id())) { qDebug() << "syncLatteViewsToScreens: view must be deleted... for containment:" << view->containment()->id() << " at screen:" << view->positioner()->currentScreenName(); auto viewToDelete = m_latteViews.take(view->containment()); viewToDelete->disconnectSensitiveSignals(); viewToDelete->deleteLater(); } } //! reconsider views foreach (auto view, m_latteViews) { if (view->containment() && futureShownViews.contains(view->containment()->id())) { //! if the dock will not be deleted its a very good point to reconsider //! if the screen in which is running is the correct one view->reconsiderScreen(); } } qDebug() << "end of, syncLatteViewsToScreens ...."; } void Layout::assignToLayout(Latte::View *latteView, QList containments) { if (!m_corona) { return; } if (latteView) { m_latteViews[latteView->containment()] = latteView; m_containments << containments; foreach (auto containment, containments) { containment->config().writeEntry("layoutId", name()); connect(containment, &QObject::destroyed, this, &Layout::containmentDestroyed); connect(containment, &Plasma::Applet::destroyedChanged, this, &Layout::destroyedChanged); connect(containment, &Plasma::Containment::appletCreated, this, &Layout::appletCreated); } latteView->setManagedLayout(this); emit viewsCountChanged(); } //! sync the original layout file for integrity - if (m_corona && m_corona->layoutManager()->memoryUsage() == Dock::MultipleLayouts) { + if (m_corona && m_corona->layoutManager()->memoryUsage() == Types::MultipleLayouts) { syncToLayoutFile(false); } } QList Layout::unassignFromLayout(Latte::View *latteView) { QList containments; if (!m_corona) { return containments; } containments << latteView->containment(); foreach (auto containment, m_containments) { Plasma::Applet *parentApplet = qobject_cast(containment->parent()); //! add systrays from that latteView if (parentApplet && parentApplet->containment() && parentApplet->containment() == latteView->containment()) { containments << containment; disconnect(containment, &QObject::destroyed, this, &Layout::containmentDestroyed); disconnect(containment, &Plasma::Applet::destroyedChanged, this, &Layout::destroyedChanged); disconnect(containment, &Plasma::Containment::appletCreated, this, &Layout::appletCreated); } } foreach (auto containment, containments) { m_containments.removeAll(containment); } if (containments.size() > 0) { m_latteViews.remove(latteView->containment()); } //! sync the original layout file for integrity - if (m_corona && m_corona->layoutManager()->memoryUsage() == Dock::MultipleLayouts) { + if (m_corona && m_corona->layoutManager()->memoryUsage() == Types::MultipleLayouts) { syncToLayoutFile(false); } return containments; } bool Layout::latteViewExists(Plasma::Containment *containment) { if (!m_corona) { return false; } return m_latteViews.keys().contains(containment); } QList Layout::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; } foreach (auto view, m_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 Layout::qmlFreeEdges(int screen) const { if (!m_corona) { const QList emptyEdges; return emptyEdges; } const auto edges = freeEdges(screen); QList edgesInt; foreach (Plasma::Types::Location edge, edges) { edgesInt.append(static_cast(edge)); } return edgesInt; } QList Layout::freeEdges(QScreen *scr) const { using Plasma::Types; QList edges{Types::BottomEdge, Types::LeftEdge, Types::TopEdge, Types::RightEdge}; if (!m_corona) { return edges; } foreach (auto view, m_latteViews) { if (view && view->positioner()->currentScreenName() == scr->name()) { edges.removeOne(view->location()); } } return edges; } QList Layout::freeEdges(int screen) const { using Plasma::Types; QList edges{Types::BottomEdge, Types::LeftEdge, Types::TopEdge, Types::RightEdge}; if (!m_corona) { return edges; } QScreen *scr = m_corona->screenPool()->screenForId(screen); foreach (auto view, m_latteViews) { if (view && scr && view->positioner()->currentScreenName() == scr->name()) { edges.removeOne(view->location()); } } return edges; } bool Layout::explicitDockOccupyEdge(int screen, Plasma::Types::Location location) const { if (!m_corona) { return false; } foreach (auto containment, m_containments) { if (isLatteContainment(containment)) { bool onPrimary = containment->config().readEntry("onPrimary", true); int id = containment->lastScreen(); Plasma::Types::Location contLocation = containment->location(); if (!onPrimary && id == screen && contLocation == location) { return true; } } } return false; } bool Layout::primaryDockOccupyEdge(Plasma::Types::Location location) const { if (!m_corona) { return false; } foreach (auto containment, m_containments) { if (isLatteContainment(containment)) { bool onPrimary = containment->config().readEntry("onPrimary", true); Plasma::Types::Location contLocation = containment->location(); if (onPrimary && contLocation == location) { return true; } } } return false; } bool Layout::isLatteContainment(Plasma::Containment *containment) const { if (!containment) { return false; } if (containment->pluginMetaData().pluginId() == "org.kde.latte.containment") { return true; } return false; } int Layout::viewsWithTasks() const { if (!m_corona) { return 0; } int result = 0; foreach (auto view, m_latteViews) { if (view->tasksPresent()) { result++; } } return result; } int Layout::viewsCount(int screen) const { if (!m_corona) { return 0; } QScreen *scr = m_corona->screenPool()->screenForId(screen); int docks{0}; foreach (auto view, m_latteViews) { if (view && view->screen() == scr && !view->containment()->destroyed()) { ++docks; } } return docks; } int Layout::viewsCount(QScreen *screen) const { if (!m_corona) { return 0; } int docks{0}; foreach (auto view, m_latteViews) { if (view && view->screen() == screen && !view->containment()->destroyed()) { ++docks; } } return docks; } int Layout::viewsCount() const { if (!m_corona) { return 0; } int docks{0}; foreach (auto view, m_latteViews) { if (view && view->containment() && !view->containment()->destroyed()) { ++docks; } } return docks; } } diff --git a/app/layoutmanager.cpp b/app/layoutmanager.cpp index 72425843..713f1d1e 100644 --- a/app/layoutmanager.cpp +++ b/app/layoutmanager.cpp @@ -1,1216 +1,1216 @@ /* * 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 "layoutmanager.h" // local #include "importer.h" #include "infoview.h" #include "launcherssignals.h" #include "layout.h" #include "screenpool.h" #include "settings/settingsdialog.h" #include "settings/universalsettings.h" #include "view/view.h" // Qt #include #include #include #include #include // KDE #include #include #include #include namespace Latte { const int MultipleLayoutsPresetId = 10; LayoutManager::LayoutManager(QObject *parent) : QObject(parent), m_importer(new Importer(this)), m_launchersSignals(new LaunchersSignals(this)), m_activitiesController(new KActivities::Controller(this)) { m_corona = qobject_cast(parent); if (m_corona) { connect(m_corona->universalSettings(), &UniversalSettings::currentLayoutNameChanged, this, &LayoutManager::currentLayoutNameChanged); connect(m_corona->universalSettings(), &UniversalSettings::showInfoWindowChanged, this, &LayoutManager::showInfoWindowChanged); m_dynamicSwitchTimer.setSingleShot(true); showInfoWindowChanged(); connect(&m_dynamicSwitchTimer, &QTimer::timeout, this, &LayoutManager::confirmDynamicSwitch); } } LayoutManager::~LayoutManager() { m_importer->deleteLater(); m_launchersSignals->deleteLater(); while (!m_activeLayouts.isEmpty()) { Layout *layout = m_activeLayouts.at(0); m_activeLayouts.removeFirst(); layout->unloadContainments(); layout->unloadLatteViews(); layout->deleteLater(); } m_activitiesController->deleteLater(); } void LayoutManager::load() { int configVer = m_corona->universalSettings()->version(); qDebug() << "Universal Settings version : " << configVer; if (configVer < 2 && QFile(QDir::homePath() + "/.config/lattedockrc").exists()) { qDebug() << "Latte must update its configuration..."; m_importer->updateOldConfiguration(); importPresets(false); } else if (!QFile(QDir::homePath() + "/.config/lattedockrc").exists()) { //startup create what is necessary.... QDir layoutDir(QDir::homePath() + "/.config/latte"); if (!layoutDir.exists()) { QDir(QDir::homePath() + "/.config").mkdir("latte"); } newLayout(i18n("My Layout")); importPresets(false); m_corona->universalSettings()->setCurrentLayoutName(i18n("My Layout")); m_corona->universalSettings()->setVersion(2); } //! Check if the multiple-layouts hidden file is present, add it if it isnt if (!QFile(QDir::homePath() + "/.config/latte/" + Layout::MultipleLayoutsName + ".layout.latte").exists()) { importPreset(MultipleLayoutsPresetId, false); } qDebug() << "Latte is loading its layouts..."; connect(m_corona->m_activityConsumer, &KActivities::Consumer::currentActivityChanged, this, &LayoutManager::currentActivityChanged); connect(m_corona->m_activityConsumer, &KActivities::Consumer::runningActivitiesChanged, this, [&]() { - if (memoryUsage() == Dock::MultipleLayouts) { + if (memoryUsage() == Types::MultipleLayouts) { syncMultipleLayoutsToActivities(); } }); loadLayouts(); } void LayoutManager::unload() { //! Unload all Layouts foreach (auto layout, m_activeLayouts) { - if (memoryUsage() == Dock::MultipleLayouts && layout->isOriginalLayout()) { + if (memoryUsage() == Types::MultipleLayouts && layout->isOriginalLayout()) { layout->syncToLayoutFile(true); } layout->unloadContainments(); layout->unloadLatteViews(); - if (memoryUsage() == Dock::MultipleLayouts && layout->isOriginalLayout()) { + if (memoryUsage() == Types::MultipleLayouts && layout->isOriginalLayout()) { clearUnloadedContainmentsFromLinkedFile(layout->unloadedContainmentsIds()); } layout->deleteLater(); } //! Cleanup pseudo-layout from Containments - if (memoryUsage() == Dock::MultipleLayouts) { + if (memoryUsage() == Types::MultipleLayouts) { // auto containmentsEntries = m_corona->config()->group("Containments"); // containmentsEntries.deleteGroup(); // containmentsEntries.sync(); } //! Remove no-needed temp files QString temp1File = QDir::homePath() + "/.config/lattedock.copy1.bak"; QString temp2File = QDir::homePath() + "/.config/lattedock.copy2.bak"; QFile file1(temp1File); QFile file2(temp2File); if (file1.exists()) file1.remove(); if (file2.exists()) file2.remove(); } Latte::Corona *LayoutManager::corona() { return m_corona; } Importer *LayoutManager::importer() { return m_importer; } LaunchersSignals *LayoutManager::launchersSignals() { return m_launchersSignals; } QString LayoutManager::currentLayoutName() const { - if (memoryUsage() == Dock::SingleLayout) { + if (memoryUsage() == Types::SingleLayout) { return m_corona->universalSettings()->currentLayoutName(); - } else if (memoryUsage() == Dock::MultipleLayouts) { + } else if (memoryUsage() == Types::MultipleLayouts) { return m_currentLayoutNameInMultiEnvironment; } return QString(); } QString LayoutManager::defaultLayoutName() const { QByteArray presetNameOrig = QString("preset" + QString::number(1)).toUtf8(); QString presetPath = m_corona->kPackage().filePath(presetNameOrig); QString presetName = Layout::layoutName(presetPath); QByteArray presetNameChars = presetName.toUtf8(); presetName = i18n(presetNameChars); return presetName; } bool LayoutManager::hasColorizer() const { foreach (auto layout, m_activeLayouts) { for (const auto *view : *layout->latteViews()) { if (view->effects()->colorizerEnabled()) { return true; } } } return false; } bool LayoutManager::layoutExists(QString layoutName) const { return m_layouts.contains(layoutName); } QStringList LayoutManager::layouts() const { return m_layouts; } QStringList LayoutManager::menuLayouts() const { QStringList fixedMenuLayouts = m_menuLayouts; //! in case the current layout isnt checked to be shown in the menus //! we must add it on top - if (!fixedMenuLayouts.contains(currentLayoutName()) && memoryUsage() == Dock::SingleLayout) { + if (!fixedMenuLayouts.contains(currentLayoutName()) && memoryUsage() == Types::SingleLayout) { fixedMenuLayouts.prepend(currentLayoutName()); - } else if (memoryUsage() == Dock::MultipleLayouts) { + } else if (memoryUsage() == Types::MultipleLayouts) { foreach (auto layout, m_activeLayouts) { if (layout->isOriginalLayout() && !fixedMenuLayouts.contains(layout->name())) { fixedMenuLayouts.prepend(layout->name()); } } } return fixedMenuLayouts; } void LayoutManager::setMenuLayouts(QStringList layouts) { if (m_menuLayouts == layouts) { return; } m_menuLayouts = layouts; emit menuLayoutsChanged(); } QStringList LayoutManager::activities() { return m_corona->m_activityConsumer->activities(); } QStringList LayoutManager::runningActivities() { return m_corona->m_activityConsumer->runningActivities(); } QStringList LayoutManager::orphanedActivities() { QStringList orphans; foreach (auto activity, activities()) { if (m_assignedLayouts[activity].isEmpty()) { orphans.append(activity); } } return orphans; } QStringList LayoutManager::presetsPaths() const { return m_presetsPaths; } QString LayoutManager::layoutPath(QString layoutName) { QString path = QDir::homePath() + "/.config/latte/" + layoutName + ".layout.latte"; if (!QFile(path).exists()) { path = ""; } return path; } -Dock::LayoutsMemoryUsage LayoutManager::memoryUsage() const +Types::LayoutsMemoryUsage LayoutManager::memoryUsage() const { return m_corona->universalSettings()->layoutsMemoryUsage(); } int LayoutManager::layoutsMemoryUsage() { return (int)m_corona->universalSettings()->layoutsMemoryUsage(); } -void LayoutManager::setMemoryUsage(Dock::LayoutsMemoryUsage memoryUsage) +void LayoutManager::setMemoryUsage(Types::LayoutsMemoryUsage memoryUsage) { m_corona->universalSettings()->setLayoutsMemoryUsage(memoryUsage); } void LayoutManager::addView(Plasma::Containment *containment, bool forceLoading, int explicitScreen) { - if (memoryUsage() == Dock::SingleLayout) { + if (memoryUsage() == Types::SingleLayout) { m_activeLayouts.at(0)->addView(containment, forceLoading, explicitScreen); - } else if (memoryUsage() == Dock::MultipleLayouts) { + } else if (memoryUsage() == Types::MultipleLayouts) { QString layoutId = containment->config().readEntry("layoutId", QString()); if (!layoutId.isEmpty()) { auto layout = activeLayout(layoutId); if (layout) { layout->addView(containment, forceLoading, explicitScreen); } } } } bool LayoutManager::latteViewExists(Latte::View *view) const { foreach (auto layout, m_activeLayouts) { for (auto it = layout->latteViews()->constBegin(), end = layout->latteViews()->constEnd(); it != end; ++it) { if (it.value() == view) { return true; } } } return false; } QHash *LayoutManager::currentLatteViews() const { - if (memoryUsage() == Dock::SingleLayout) { + if (memoryUsage() == Types::SingleLayout) { return m_activeLayouts.at(0)->latteViews(); } else { foreach (auto layout, m_activeLayouts) { if (layout->activities().contains(m_corona->m_activityConsumer->currentActivity())) { return layout->latteViews(); } } foreach (auto layout, m_activeLayouts) { if ((layout->name() != Layout::MultipleLayoutsName) && (layout->activities().isEmpty())) { return layout->latteViews(); } } } return nullptr; } QHash *LayoutManager::layoutLatteViews(const QString &layoutName) const { Layout *layout = activeLayout(layoutName); if (layout) { return layout->latteViews(); } return nullptr; } QStringList LayoutManager::activeLayoutsNames() { QStringList names; - if (memoryUsage() == Dock::SingleLayout) { + if (memoryUsage() == Types::SingleLayout) { names << currentLayoutName(); } else { for (int i = 0; i < m_activeLayouts.size(); ++i) { Layout *layout = m_activeLayouts.at(i); if (layout->isOriginalLayout()) { names << layout->name(); } } } return names; } Layout *LayoutManager::activeLayout(QString id) const { for (int i = 0; i < m_activeLayouts.size(); ++i) { Layout *layout = m_activeLayouts.at(i); if (layout->name() == id) { return layout; } } return nullptr; } int LayoutManager::activeLayoutPos(QString id) const { for (int i = 0; i < m_activeLayouts.size(); ++i) { Layout *layout = m_activeLayouts.at(i); if (layout->name() == id) { return i; } } return -1; } void LayoutManager::updateCurrentLayoutNameInMultiEnvironment() { foreach (auto layout, m_activeLayouts) { if (layout->isOriginalLayout() && layout->activities().contains(m_corona->activitiesConsumer()->currentActivity())) { m_currentLayoutNameInMultiEnvironment = layout->name(); emit currentLayoutNameChanged(); return; } } foreach (auto layout, m_activeLayouts) { if (layout->isOriginalLayout() && layout->activities().isEmpty()) { m_currentLayoutNameInMultiEnvironment = layout->name(); emit currentLayoutNameChanged(); return; } } } void LayoutManager::currentActivityChanged(const QString &id) { - if (memoryUsage() == Dock::SingleLayout) { + if (memoryUsage() == Types::SingleLayout) { qDebug() << "activity changed :: " << id; m_shouldSwitchToLayout = shouldSwitchToLayout(id); m_dynamicSwitchTimer.start(); - } else if (memoryUsage() == Dock::MultipleLayouts) { + } else if (memoryUsage() == Types::MultipleLayouts) { updateCurrentLayoutNameInMultiEnvironment(); } } void LayoutManager::showInfoWindowChanged() { if (m_corona->universalSettings()->showInfoWindow()) { m_dynamicSwitchTimer.setInterval(1800); } else { m_dynamicSwitchTimer.setInterval(2300); } } QString LayoutManager::shouldSwitchToLayout(QString activityId) { if (m_assignedLayouts.contains(activityId) && m_assignedLayouts[activityId] != currentLayoutName()) { return m_assignedLayouts[activityId]; } else if (!m_assignedLayouts.contains(activityId) && !m_corona->universalSettings()->lastNonAssignedLayoutName().isEmpty() && m_corona->universalSettings()->lastNonAssignedLayoutName() != currentLayoutName()) { return m_corona->universalSettings()->lastNonAssignedLayoutName(); } return QString(); } void LayoutManager::confirmDynamicSwitch() { QString tempShouldSwitch = shouldSwitchToLayout(m_corona->m_activityConsumer->currentActivity()); if (tempShouldSwitch.isEmpty()) { return; } if (m_shouldSwitchToLayout == tempShouldSwitch && m_shouldSwitchToLayout != currentLayoutName()) { qDebug() << "dynamic switch to layout :: " << m_shouldSwitchToLayout; emit currentLayoutIsSwitching(currentLayoutName()); if (m_corona->universalSettings()->showInfoWindow()) { showInfoWindow(i18n("Switching to layout %0 ...").arg(m_shouldSwitchToLayout), 4000); } QTimer::singleShot(500, [this, tempShouldSwitch]() { switchToLayout(tempShouldSwitch); }); } else { m_shouldSwitchToLayout = tempShouldSwitch; m_dynamicSwitchTimer.start(); } } void LayoutManager::loadLayouts() { m_layouts.clear(); m_menuLayouts.clear(); m_presetsPaths.clear(); m_assignedLayouts.clear(); QDir layoutDir(QDir::homePath() + "/.config/latte"); QStringList filter; filter.append(QString("*.layout.latte")); QStringList files = layoutDir.entryList(filter, QDir::Files | QDir::NoSymLinks); foreach (auto layout, files) { Layout layoutSets(this, layoutDir.absolutePath() + "/" + layout); QStringList validActivityIds = validActivities(layoutSets.activities()); layoutSets.setActivities(validActivityIds); foreach (auto activity, validActivityIds) { m_assignedLayouts[activity] = layoutSets.name(); } m_layouts.append(layoutSets.name()); if (layoutSets.showInMenu()) { m_menuLayouts.append(layoutSets.name()); } } m_presetsPaths.append(m_corona->kPackage().filePath("preset1")); m_presetsPaths.append(m_corona->kPackage().filePath("preset2")); m_presetsPaths.append(m_corona->kPackage().filePath("preset3")); m_presetsPaths.append(m_corona->kPackage().filePath("preset4")); emit layoutsChanged(); emit menuLayoutsChanged(); } void LayoutManager::loadLayoutOnStartup(QString layoutName) { - // if (memoryUsage() == Dock::MultipleLayouts) { + // if (memoryUsage() == Types::MultipleLayouts) { QStringList layouts = m_importer->checkRepairMultipleLayoutsLinkedFile(); //! Latte didn't close correctly, maybe a crash if (layouts.size() > 0) { QMessageBox *msg = new QMessageBox(); msg->setAttribute(Qt::WA_DeleteOnClose); msg->setIcon(QMessageBox::Warning); msg->setWindowTitle(i18n("Multiple Layouts Warning")); msg->setText(i18n("Latte did not close properly in the previous session. The following layout(s) [%0] were updated for consistency!!!").arg(layouts.join(","))); msg->setStandardButtons(QMessageBox::Ok); msg->open(); } //} switchToLayout(layoutName); } void LayoutManager::loadLatteLayout(QString layoutPath) { qDebug() << " -------------------------------------------------------------------- "; qDebug() << " -------------------------------------------------------------------- "; if (m_corona->containments().size() > 0) { qDebug() << "LOAD LATTE LAYOUT ::: There are still containments present !!!! :: " << m_corona->containments().size(); } if (!layoutPath.isEmpty() && m_corona->containments().size() == 0) { cleanupOnStartup(layoutPath); qDebug() << "LOADING CORONA LAYOUT:" << layoutPath; m_corona->loadLayout(layoutPath); //! ~~~ ADDING LATTEVIEWS AND ENFORCE LOADING IF TASKS ARENT PRESENT BASED ON SCREENS ~~~ !// //! this is used to record the first dock having tasks in it. It is used //! to specify which dock will be loaded on startup if a case that no "dock //! with tasks" will be loaded otherwise. Currently the older one dock wins /*int firstContainmentWithTasks = -1; //! this is used to check if a dock with tasks in it will be loaded on startup bool tasksWillBeLoaded = heuresticForLoadingDockWithTasks(&firstContainmentWithTasks); qDebug() << "TASKS WILL BE PRESENT AFTER LOADING ::: " << tasksWillBeLoaded; foreach (auto containment, m_corona->containments()) { //! forceDockLoading is used when a latte configuration based on the //! current running screens does not provide a dock containing tasks. //! in such case the lowest latte containment containing tasks is loaded //! and it forcefully becomes primary dock if (!tasksWillBeLoaded && firstContainmentWithTasks == containment->id()) { tasksWillBeLoaded = true; //this protects by loading more than one dock at startup addDock(containment, true); } else { addDock(containment); } }*/ } } void LayoutManager::cleanupOnStartup(QString path) { KSharedConfigPtr filePtr = KSharedConfig::openConfig(path); KConfigGroup actionGroups = KConfigGroup(filePtr, "ActionPlugins"); QStringList deprecatedActionGroup; foreach (auto actId, actionGroups.groupList()) { QString pluginId = actionGroups.group(actId).readEntry("RightButton;NoModifier", ""); if (pluginId == "org.kde.contextmenu") { deprecatedActionGroup << actId; } } foreach (auto pId, deprecatedActionGroup) { qDebug() << "!!!!!!!!!!!!!!!! !!!!!!!!!!!! !!!!!!! REMOVING :::: " << pId; actionGroups.group(pId).deleteGroup(); } KConfigGroup containmentGroups = KConfigGroup(filePtr, "Containments"); QStringList removeContaimentsList; foreach (auto cId, containmentGroups.groupList()) { QString pluginId = containmentGroups.group(cId).readEntry("plugin", ""); if (pluginId == "org.kde.desktopcontainment") { //!must remove ghost containments first removeContaimentsList << cId; } } foreach (auto cId, removeContaimentsList) { containmentGroups.group(cId).deleteGroup(); } actionGroups.sync(); containmentGroups.sync(); } void LayoutManager::showAboutDialog() { m_corona->aboutApplication(); } void LayoutManager::importLatteLayout(QString layoutPath) { //! This might not be needed as it is Layout responsibility } void LayoutManager::hideAllViews() { foreach (auto layout, m_activeLayouts) { if (layout->isOriginalLayout()) { emit currentLayoutIsSwitching(layout->name()); } } } void LayoutManager::addLayout(Layout *layout) { if (!m_activeLayouts.contains(layout)) { m_activeLayouts.append(layout); layout->initToCorona(m_corona); connect(layout, &Layout::viewColorizerChanged, this, &LayoutManager::viewColorizerChanged); } } bool LayoutManager::switchToLayout(QString layoutName, int previousMemoryUsage) { if (m_activeLayouts.size() > 0 && currentLayoutName() == layoutName && previousMemoryUsage == -1) { return false; } //! First Check If that Layout is already present - if (memoryUsage() == Dock::MultipleLayouts && previousMemoryUsage == -1) { + if (memoryUsage() == Types::MultipleLayouts && previousMemoryUsage == -1) { Layout *layout = activeLayout(layoutName); if (layout) { QStringList appliedActivities = layout->appliedActivities(); QString nextActivity = !layout->lastUsedActivity().isEmpty() ? layout->lastUsedActivity() : appliedActivities[0]; //! it means we are at a foreign activity if (!appliedActivities.contains(m_corona->activitiesConsumer()->currentActivity())) { m_activitiesController->setCurrentActivity(nextActivity); return true; } } } //! When going from memory usage to different memory usage we first //! send the layouts that will be changed. This signal creates the //! nice animation that hides these docks/panels if (previousMemoryUsage != -1) { foreach (auto layout, m_activeLayouts) { if (layout->isOriginalLayout()) { emit currentLayoutIsSwitching(layout->name()); } } } QString lPath = layoutPath(layoutName); if (lPath.isEmpty() && layoutName == i18n("Alternative")) { lPath = newLayout(i18n("Alternative"), i18n("Default")); } if (!lPath.isEmpty()) { - if (memoryUsage() == Dock::SingleLayout) { + if (memoryUsage() == Types::SingleLayout) { emit currentLayoutIsSwitching(currentLayoutName()); - } else if (memoryUsage() == Dock::MultipleLayouts && layoutName != Layout::MultipleLayoutsName) { + } else if (memoryUsage() == Types::MultipleLayouts && layoutName != Layout::MultipleLayoutsName) { Layout toLayout(this, lPath); QStringList toActivities = toLayout.activities(); Layout *activeForOrphans{nullptr}; foreach (auto fromLayout, m_activeLayouts) { if (fromLayout->isOriginalLayout() && fromLayout->activities().isEmpty()) { activeForOrphans = fromLayout; break; } } if (toActivities.isEmpty() && activeForOrphans && (toLayout.name() != activeForOrphans->name())) { emit currentLayoutIsSwitching(activeForOrphans->name()); } } //! this code must be called asynchronously because it is called //! also from qml (Tasks plasmoid). This change fixes a very important //! crash when switching sessions through the Tasks plasmoid Context menu //! Latte was unstable and was crashing very often during changing //! sessions. QTimer::singleShot(350, [this, layoutName, lPath, previousMemoryUsage]() { qDebug() << layoutName << " - " << lPath; QString fixedLPath = lPath; QString fixedLayoutName = layoutName; bool initializingMultipleLayouts{false}; - if (memoryUsage() == Dock::MultipleLayouts && !activeLayout(Layout::MultipleLayoutsName)) { + if (memoryUsage() == Types::MultipleLayouts && !activeLayout(Layout::MultipleLayoutsName)) { initializingMultipleLayouts = true; } - if (memoryUsage() == Dock::SingleLayout || initializingMultipleLayouts || previousMemoryUsage == Dock::MultipleLayouts) { + if (memoryUsage() == Types::SingleLayout || initializingMultipleLayouts || previousMemoryUsage == Types::MultipleLayouts) { while (!m_activeLayouts.isEmpty()) { Layout *layout = m_activeLayouts.at(0); m_activeLayouts.removeFirst(); - if (layout->isOriginalLayout() && previousMemoryUsage == Dock::MultipleLayouts) { + if (layout->isOriginalLayout() && previousMemoryUsage == Types::MultipleLayouts) { layout->syncToLayoutFile(true); } layout->unloadContainments(); layout->unloadLatteViews(); - if (layout->isOriginalLayout() && previousMemoryUsage == Dock::MultipleLayouts) { + if (layout->isOriginalLayout() && previousMemoryUsage == Types::MultipleLayouts) { clearUnloadedContainmentsFromLinkedFile(layout->unloadedContainmentsIds(), true); } delete layout; } if (initializingMultipleLayouts) { fixedLayoutName = QString(Layout::MultipleLayoutsName); fixedLPath = layoutPath(fixedLayoutName); } Layout *newLayout = new Layout(this, fixedLPath, fixedLayoutName); addLayout(newLayout); loadLatteLayout(fixedLPath); emit activeLayoutsChanged(); } - if (memoryUsage() == Dock::MultipleLayouts) { + if (memoryUsage() == Types::MultipleLayouts) { if (!initializingMultipleLayouts && !activeLayout(layoutName)) { //! When we are in Multiple Layouts Environment and the user activates //! a Layout that is assigned to specific activities but this //! layout isnt loaded (this means neither of its activities are running) //! is such case we just activate these Activities Layout layout(this, Importer::layoutFilePath(layoutName)); int i = 0; bool lastUsedActivityFound{false}; QString lastUsedActivity = layout.lastUsedActivity(); bool orphanedLayout = !layoutIsAssigned(layoutName); QStringList assignedActivities = orphanedLayout ? orphanedActivities() : layout.activities(); if (!orphanedLayout) { foreach (auto assignedActivity, assignedActivities) { //! Starting the activities must be done asynchronous because otherwise //! the activity manager cant close multiple activities QTimer::singleShot(i * 1000, [this, assignedActivity, lastUsedActivity]() { m_activitiesController->startActivity(assignedActivity); if (lastUsedActivity == assignedActivity) { m_activitiesController->setCurrentActivity(lastUsedActivity); } }); if (lastUsedActivity == assignedActivity) { lastUsedActivityFound = true; } i = i + 1; } } else { //! orphaned layout foreach (auto assignedActivity, assignedActivities) { if (lastUsedActivity == assignedActivity) { lastUsedActivityFound = true; } } if ((!lastUsedActivityFound && assignedActivities.count() == 0) || !assignedActivities.contains(m_corona->m_activityConsumer->currentActivity())) { //! Starting the activities must be done asynchronous because otherwise //! the activity manager cant close multiple activities QTimer::singleShot(1000, [this, lastUsedActivity, lastUsedActivityFound]() { m_activitiesController->startActivity(lastUsedActivity); m_activitiesController->setCurrentActivity(lastUsedActivity); }); } } if (orphanedLayout) { syncMultipleLayoutsToActivities(layoutName); } else if (!orphanedLayout && !lastUsedActivityFound) { m_activitiesController->setCurrentActivity(layout.activities()[0]); } } else { syncMultipleLayoutsToActivities(layoutName); } } m_corona->universalSettings()->setCurrentLayoutName(layoutName); if (!layoutIsAssigned(layoutName)) { m_corona->universalSettings()->setLastNonAssignedLayoutName(layoutName); } }); } else { qDebug() << "Layout : " << layoutName << " was not found..."; } return true; } void LayoutManager::syncMultipleLayoutsToActivities(QString layoutForOrphans) { qDebug() << " ---- --------- ------ syncMultipleLayoutsToActivities ------- "; qDebug() << " ---- --------- ------ ------------------------------- ------- "; QStringList layoutsToUnload; QStringList layoutsToLoad; layoutsToLoad << Layout::MultipleLayoutsName; bool allRunningActivitiesWillBeReserved{true}; if (layoutForOrphans.isEmpty() || m_assignedLayouts.values().contains(layoutForOrphans)) { layoutForOrphans = m_corona->universalSettings()->lastNonAssignedLayoutName(); } foreach (auto activity, runningActivities()) { if (!m_assignedLayouts[activity].isEmpty()) { if (!layoutsToLoad.contains(m_assignedLayouts[activity])) { layoutsToLoad.append(m_assignedLayouts[activity]); } } else { allRunningActivitiesWillBeReserved = false; } } foreach (auto layout, m_activeLayouts) { QString tempLayoutName; if (!layoutsToLoad.contains(layout->name()) && layout->name() != layoutForOrphans) { tempLayoutName = layout->name(); } else if (layout->activities().isEmpty() && allRunningActivitiesWillBeReserved) { //! in such case the layout for the orphaned must be unloaded tempLayoutName = layout->name(); } if (!tempLayoutName.isEmpty() && !layoutsToUnload.contains(tempLayoutName)) { layoutsToUnload << tempLayoutName; } } //! Unload no needed Layouts foreach (auto layoutName, layoutsToUnload) { if (layoutName != Layout::MultipleLayoutsName) { Layout *layout = activeLayout(layoutName); int posLayout = activeLayoutPos(layoutName); if (posLayout >= 0) { qDebug() << "REMOVING LAYOUT ::::: " << layoutName; m_activeLayouts.removeAt(posLayout); if (layout->isOriginalLayout()) { layout->syncToLayoutFile(true); } layout->unloadContainments(); layout->unloadLatteViews(); clearUnloadedContainmentsFromLinkedFile(layout->unloadedContainmentsIds()); delete layout; } } } //! Add Layout for orphan activities if (!allRunningActivitiesWillBeReserved) { if (!activeLayout(layoutForOrphans)) { Layout *newLayout = new Layout(this, layoutPath(layoutForOrphans), layoutForOrphans); if (newLayout) { qDebug() << "ACTIVATING ORPHANED LAYOUT ::::: " << layoutForOrphans; addLayout(newLayout); newLayout->importToCorona(); } } } //! Add needed Layouts based on Activities foreach (auto layoutName, layoutsToLoad) { if (!activeLayout(layoutName)) { Layout *newLayout = new Layout(this, QString(layoutPath(layoutName)), layoutName); if (newLayout) { qDebug() << "ACTIVATING LAYOUT ::::: " << layoutName; addLayout(newLayout); newLayout->importToCorona(); if (newLayout->isOriginalLayout() && m_corona->universalSettings()->showInfoWindow()) { showInfoWindow(i18n("Activating layout: %0 ...").arg(newLayout->name()), 5000, newLayout->appliedActivities()); } } } } updateCurrentLayoutNameInMultiEnvironment(); emit activeLayoutsChanged(); } void LayoutManager::pauseLayout(QString layoutName) { - if (memoryUsage() == Dock::MultipleLayouts) { + if (memoryUsage() == Types::MultipleLayouts) { Layout *layout = activeLayout(layoutName); if (layout && !layout->activities().isEmpty()) { int i = 0; foreach (auto activityId, layout->activities()) { //! Stopping the activities must be done asynchronous because otherwise //! the activity manager cant close multiple activities QTimer::singleShot(i * 1000, [this, activityId]() { m_activitiesController->stopActivity(activityId); }); i = i + 1; } } } } void LayoutManager::syncActiveLayoutsToOriginalFiles() { - if (memoryUsage() == Dock::MultipleLayouts) { + if (memoryUsage() == Types::MultipleLayouts) { foreach (auto layout, m_activeLayouts) { if (layout->isOriginalLayout()) { layout->syncToLayoutFile(); } } } } void LayoutManager::clearUnloadedContainmentsFromLinkedFile(QStringList containmentsIds, bool bypassChecks) { - if (!m_corona || (memoryUsage() == Dock::SingleLayout && !bypassChecks)) { + if (!m_corona || (memoryUsage() == Types::SingleLayout && !bypassChecks)) { return; } auto containments = m_corona->config()->group("Containments"); foreach (auto conId, containmentsIds) { qDebug() << "unloads ::: " << conId; KConfigGroup containment = containments.group(conId); containment.deleteGroup(); } containments.sync(); } void LayoutManager::syncLatteViewsToScreens() { foreach (auto layout, m_activeLayouts) { layout->syncLatteViewsToScreens(); } } QString LayoutManager::newLayout(QString layoutName, QString preset) { QDir layoutDir(QDir::homePath() + "/.config/latte"); QStringList filter; filter.append(QString(layoutName + "*.layout.latte")); QStringList files = layoutDir.entryList(filter, QDir::Files | QDir::NoSymLinks); //! if the newLayout already exists provide a newName that doesn't if (files.count() >= 1) { int newCounter = files.count() + 1; layoutName = layoutName + "-" + QString::number(newCounter); } QString newLayoutPath = layoutDir.absolutePath() + "/" + layoutName + ".layout.latte"; qDebug() << "adding layout : " << layoutName << " based on preset:" << preset; if (preset == i18n("Default") && !QFile(newLayoutPath).exists()) { qDebug() << "adding layout : succeed"; QFile(m_corona->kPackage().filePath("preset1")).copy(newLayoutPath); } return newLayoutPath; } //! This function figures in the beginning if a view with tasks //! in it will be loaded taking into account also the screens are present. bool LayoutManager::heuresticForLoadingViewWithTasks(int *firstContainmentWithTasks) { foreach (auto containment, m_corona->containments()) { QString plugin = containment->pluginMetaData().pluginId(); if (plugin == "org.kde.latte.containment") { bool onPrimary = containment->config().readEntry("onPrimary", true); int lastScreen = containment->lastScreen(); qDebug() << "containment values: " << onPrimary << " - " << lastScreen; bool containsTasks = false; foreach (auto applet, containment->applets()) { const auto &provides = KPluginMetaData::readStringList(applet->pluginMetaData().rawData(), QStringLiteral("X-Plasma-Provides")); if (provides.contains(QLatin1String("org.kde.plasma.multitasking"))) { containsTasks = true; break; } } if (containsTasks) { *firstContainmentWithTasks = containment->id(); if (onPrimary) { return true; } else { if (lastScreen >= 0) { QString connector = m_corona->screenPool()->connector(lastScreen); foreach (auto scr, qGuiApp->screens()) { if (scr && scr->name() == connector) { return true; break; } } } } } } } return false; } void LayoutManager::importDefaultLayout(bool newInstanceIfPresent) { importPreset(1, newInstanceIfPresent); if (newInstanceIfPresent) { loadLayouts(); } } void LayoutManager::importPresets(bool includeDefault) { int start = 1; if (!includeDefault) { start = 2; } for (int i = start; i <= 4; ++i) { importPreset(i, false); } } void LayoutManager::importPreset(int presetNo, bool newInstanceIfPresent) { QByteArray presetNameOrig = QString("preset" + QString::number(presetNo)).toUtf8(); QString presetPath = m_corona->kPackage().filePath(presetNameOrig); QString presetName = Layout::layoutName(presetPath); QByteArray presetNameChars = presetName.toUtf8(); presetName = i18n(presetNameChars); //! hide the multiple layouts layout file from user presetName = (presetNo == MultipleLayoutsPresetId) ? "." + presetName : presetName; QString newLayoutFile = ""; if (newInstanceIfPresent) { newLayoutFile = QDir::homePath() + "/.config/latte/" + m_importer->uniqueLayoutName(presetName) + ".layout.latte"; } else { newLayoutFile = QDir::homePath() + "/.config/latte/" + presetName + ".layout.latte"; } if (!QFile(newLayoutFile).exists()) { QFile(presetPath).copy(newLayoutFile); QFileInfo newFileInfo(newLayoutFile); if (newFileInfo.exists() && !newFileInfo.isWritable()) { QFile(newLayoutFile).setPermissions(QFileDevice::ReadUser | QFileDevice::WriteUser | QFileDevice::ReadGroup | QFileDevice::ReadOther); } } } QStringList LayoutManager::validActivities(QStringList currentList) { QStringList validIds; foreach (auto activity, currentList) { if (activities().contains(activity)) { validIds.append(activity); } } return validIds; } bool LayoutManager::layoutIsAssigned(QString layoutName) { QHashIterator i(m_assignedLayouts); while (i.hasNext()) { i.next(); if (i.value() == layoutName) { return true; } } return false; } void LayoutManager::showLatteSettingsDialog(int page) { if (!m_latteSettingsDialog) { m_latteSettingsDialog = new SettingsDialog(nullptr, m_corona); } m_latteSettingsDialog->show(); if (m_latteSettingsDialog->isMinimized()) { m_latteSettingsDialog->showNormal(); } - Dock::LatteConfigPage configPage = static_cast(page); + Types::LatteConfigPage configPage = static_cast(page); m_latteSettingsDialog->setCurrentPage(configPage); m_latteSettingsDialog->activateWindow(); } void LayoutManager::hideLatteSettingsDialog() { if (m_latteSettingsDialog) { m_latteSettingsDialog->deleteLater(); m_latteSettingsDialog = nullptr; } } void LayoutManager::showInfoWindow(QString info, int duration, QStringList activities) { foreach (auto screen, qGuiApp->screens()) { InfoView *infoView = new InfoView(m_corona, info, screen); infoView->show(); infoView->setOnActivities(activities); QTimer::singleShot(duration, [this, infoView]() { infoView->deleteLater(); }); } } //! it is used just in order to provide translations for the presets void LayoutManager::ghostForTranslatedPresets() { QString preset1 = i18n("Default"); QString preset2 = i18n("Plasma"); QString preset3 = i18n("Unity"); QString preset4 = i18n("Extended"); } } diff --git a/app/layoutmanager.h b/app/layoutmanager.h index 037a49e4..4aa66152 100644 --- a/app/layoutmanager.h +++ b/app/layoutmanager.h @@ -1,202 +1,202 @@ /* * 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 LAYOUTMANAGER_H #define LAYOUTMANAGER_H // local #include "launcherssignals.h" #include "settings/settingsdialog.h" // Qt #include #include #include // KDE #include namespace Plasma { class Containment; class Types; } namespace KActivities { class Controller; } namespace Latte { class Corona; class Importer; class Layout; class LaunchersSignals; class View; } namespace Latte { //! This class is responsible to manipulate all layouts. //! add,remove,rename, update configurations etc. class LayoutManager : public QObject { Q_OBJECT Q_PROPERTY(QString currentLayoutName READ currentLayoutName NOTIFY currentLayoutNameChanged) Q_PROPERTY(QStringList layouts READ layouts NOTIFY layoutsChanged) Q_PROPERTY(QStringList menuLayouts READ menuLayouts NOTIFY menuLayoutsChanged) Q_PROPERTY(LaunchersSignals *launchersSignals READ launchersSignals NOTIFY launchersSignalsChanged) public: LayoutManager(QObject *parent = nullptr); ~LayoutManager() override; Latte::Corona *corona(); Importer *importer(); void load(); void loadLayoutOnStartup(QString layoutName); void unload(); void addView(Plasma::Containment *containment, bool forceLoading = false, int explicitScreen = -1); void hideAllViews(); void pauseLayout(QString layoutName); void syncLatteViewsToScreens(); void syncActiveLayoutsToOriginalFiles(); bool latteViewExists(Latte::View *view) const; bool hasColorizer() const; bool layoutExists(QString layoutName) const; QString shouldSwitchToLayout(QString activityId); QString currentLayoutName() const; QString defaultLayoutName() const; QStringList layouts() const; QStringList menuLayouts() const; QStringList presetsPaths() const; - Dock::LayoutsMemoryUsage memoryUsage() const; - void setMemoryUsage(Dock::LayoutsMemoryUsage memoryUsage); + Types::LayoutsMemoryUsage memoryUsage() const; + void setMemoryUsage(Types::LayoutsMemoryUsage memoryUsage); QHash *currentLatteViews() const; QHash *layoutLatteViews(const QString &layoutName) const; //! returns an active layout with that #id (name), it returns null if such //! layout cant be found Layout *activeLayout(QString id) const; int activeLayoutPos(QString id) const; LaunchersSignals *launchersSignals(); QStringList activities(); QStringList runningActivities(); QStringList orphanedActivities(); //! These are activities that havent been assigned to specific layout void importDefaultLayout(bool newInstanceIfPresent = false); void importPresets(bool includeDefault = false); public slots: void showAboutDialog(); void hideLatteSettingsDialog(); - Q_INVOKABLE void showLatteSettingsDialog(int page = Latte::Dock::LayoutPage); + Q_INVOKABLE void showLatteSettingsDialog(int page = Latte::Types::LayoutPage); //! switch to specified layout, default previousMemoryUsage means that it didn't change Q_INVOKABLE bool switchToLayout(QString layoutName, int previousMemoryUsage = -1); Q_INVOKABLE int layoutsMemoryUsage(); //! creates a new layout with layoutName based on the preset Q_INVOKABLE QString newLayout(QString layoutName, QString preset = i18n("Default")); Q_INVOKABLE QStringList activeLayoutsNames(); signals: void activeLayoutsChanged(); void currentLayoutChanged(); void currentLayoutNameChanged(); void launchersSignalsChanged(); void layoutsChanged(); void menuLayoutsChanged(); void viewColorizerChanged(); void currentLayoutIsSwitching(QString layoutName); private slots: void currentActivityChanged(const QString &id); void showInfoWindowChanged(); void syncMultipleLayoutsToActivities(QString layoutForOrphans = QString()); private: void addLayout(Layout *layout); void cleanupOnStartup(QString path); //!remove deprecated or oldstyle config options void clearUnloadedContainmentsFromLinkedFile(QStringList containmentsIds, bool bypassChecks = false); void confirmDynamicSwitch(); //! it is used just in order to provide translations for the presets void ghostForTranslatedPresets(); //! This function figures in the beginning if a view with tasks //! in it will be loaded taking into account also the screens are present. //! returns true if it will be loaded, false otherwise //! firstContainmentWithTasks = the first containment containing a taskmanager plasmoid bool heuresticForLoadingViewWithTasks(int *firstContainmentWithTasks); void importLatteLayout(QString layoutPath); void importPreset(int presetNo, bool newInstanceIfPresent = false); void loadLatteLayout(QString layoutPath); void loadLayouts(); void setMenuLayouts(QStringList layouts); void showInfoWindow(QString info, int duration, QStringList activities = {"0"}); void updateCurrentLayoutNameInMultiEnvironment(); bool layoutIsAssigned(QString layoutName); QString layoutPath(QString layoutName); QStringList validActivities(QStringList currentList); private: QString m_currentLayoutNameInMultiEnvironment; QString m_shouldSwitchToLayout; QStringList m_layouts; QStringList m_menuLayouts; QStringList m_presetsPaths; QHash m_assignedLayouts; QTimer m_dynamicSwitchTimer; QPointer m_latteSettingsDialog; Latte::Corona *m_corona{nullptr}; Importer *m_importer{nullptr}; LaunchersSignals *m_launchersSignals{nullptr}; QList m_activeLayouts; KActivities::Controller *m_activitiesController; friend class SettingsDialog; }; } #endif // LAYOUTMANAGER_H diff --git a/app/main.cpp b/app/main.cpp index 507e4e73..9e055969 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -1,316 +1,316 @@ /* * 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 . */ // local #include "config-latte.h" #include "importer.h" #include "lattecorona.h" -#include "../liblattedock/dock.h" +#include "../liblatte2/types.h" // C++ #include #include // Qt #include #include #include #include #include #include #include #include // KDE #include #include #include #include #include //! COLORS #define CNORMAL "\e[0m" #define CIGREEN "\e[1;32m" #define CGREEN "\e[0;32m" #define CICYAN "\e[1;36m" #define CCYAN "\e[0;36m" #define CIRED "\e[1;31m" #define CRED "\e[0;31m" inline void configureAboutData(); inline void detectPlatform(int argc, char **argv); int main(int argc, char **argv) { //Plasma scales itself to font DPI //on X, where we don't have compositor scaling, this generally works fine. //also there are bugs on older Qt, especially when it comes to fractional scaling //there's advantages to disabling, and (other than small context menu icons) few advantages in enabling //On wayland, it's different. Everything is simpler as all co-ordinates are in the same co-ordinate system //we don't have fractional scaling on the client so don't hit most the remaining bugs and //even if we don't use Qt scaling the compositor will try to scale us anyway so we have no choice if (!qEnvironmentVariableIsSet("PLASMA_USE_QT_SCALING")) { qunsetenv("QT_DEVICE_PIXEL_RATIO"); QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling); } else { QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); } QQuickWindow::setDefaultAlphaBuffer(true); const bool qpaVariable = qEnvironmentVariableIsSet("QT_QPA_PLATFORM"); detectPlatform(argc, argv); QApplication app(argc, argv); if (!qpaVariable) { // don't leak the env variable to processes we start qunsetenv("QT_QPA_PLATFORM"); } KQuickAddons::QtQuickSettings::init(); KLocalizedString::setApplicationDomain("latte-dock"); app.setWindowIcon(QIcon::fromTheme(QStringLiteral("latte-dock"))); //protect from closing app when changing to "alternative session" and back app.setQuitOnLastWindowClosed(false); configureAboutData(); QCommandLineParser parser; parser.addHelpOption(); parser.addVersionOption(); parser.addOptions({ {{"r", "replace"}, i18nc("command line", "Replace the current Latte instance.")} , {{"d", "debug"}, i18nc("command line", "Show the debugging messages on stdout.")} , {"default-layout", i18nc("command line", "Import and load default layout on startup.")} , {"available-layouts", i18nc("command line", "Print available layouts")} , {"layout", i18nc("command line", "Load specific layout on startup."), i18nc("command line: load", "layout_name")} , {"import-layout", i18nc("command line", "Import and load a layout."), i18nc("command line: import", "file_name")} , {"import-full", i18nc("command line", "Import full configuration."), i18nc("command line: import", "file_name")} , {"single", i18nc("command line", "Single layout memory mode. Only one layout is active at any case.")} , {"multiple", i18nc("command line", "Multiple layouts memory mode. Multiple layouts can be active at any time based on Activities running.")} }); //! START: Hidden options for Developer and Debugging usage QCommandLineOption graphicsOption(QStringList() << QStringLiteral("graphics")); graphicsOption.setDescription(QStringLiteral("Draw boxes around of the applets.")); graphicsOption.setHidden(true); parser.addOption(graphicsOption); QCommandLineOption withWindowOption(QStringList() << QStringLiteral("with-window")); withWindowOption.setDescription(QStringLiteral("Open a window with much debug information")); withWindowOption.setHidden(true); parser.addOption(withWindowOption); QCommandLineOption maskOption(QStringList() << QStringLiteral("mask")); maskOption.setDescription(QStringLiteral("Show messages of debugging for the mask (Only useful to devs).")); maskOption.setHidden(true); parser.addOption(maskOption); QCommandLineOption timersOption(QStringList() << QStringLiteral("timers")); timersOption.setDescription(QStringLiteral("Show messages for debugging the timers (Only useful to devs).")); timersOption.setHidden(true); parser.addOption(timersOption); QCommandLineOption spacersOption(QStringList() << QStringLiteral("spacers")); spacersOption.setDescription(QStringLiteral("Show visual indicators for debugging spacers (Only useful to devs).")); spacersOption.setHidden(true); parser.addOption(spacersOption); QCommandLineOption overloadedIconsOption(QStringList() << QStringLiteral("overloaded-icons")); overloadedIconsOption.setDescription(QStringLiteral("Show visual indicators for debugging overloaded applets icons (Only useful to devs).")); overloadedIconsOption.setHidden(true); parser.addOption(overloadedIconsOption); //! END: Hidden options parser.process(app); if (parser.isSet(QStringLiteral("available-layouts"))) { QStringList layouts = Latte::Importer::availableLayouts(); if (layouts.count() > 0) { qInfo() << i18n("Available layouts that can be used to start Latte:"); foreach (auto layout, layouts) { qInfo() << " " << layout; } } else { qInfo() << i18n("There are no available layouts, during startup Default will be used."); } qGuiApp->exit(); return 0; } bool defaultLayoutOnStartup = false; int memoryUsage = -1; QString layoutNameOnStartup = ""; if (parser.isSet(QStringLiteral("default-layout"))) { defaultLayoutOnStartup = true; } else if (parser.isSet(QStringLiteral("layout"))) { layoutNameOnStartup = parser.value(QStringLiteral("layout")); if (!Latte::Importer::layoutExists(layoutNameOnStartup)) { qInfo() << i18nc("layout missing", "This layout doesn't exist in the system."); qGuiApp->exit(); return 0; } } QString username = qgetenv("USER"); if (username.isEmpty()) username = qgetenv("USERNAME"); QLockFile lockFile {QDir::tempPath() + "/latte-dock." + username + ".lock"}; int timeout {100}; if (parser.isSet(QStringLiteral("replace")) || parser.isSet(QStringLiteral("import-full"))) { qint64 pid{ -1}; if (lockFile.getLockInfo(&pid, nullptr, nullptr)) { kill(static_cast(pid), SIGINT); timeout = 3000; } } if (!lockFile.tryLock(timeout)) { qInfo() << i18n("An instance is already running!, use --replace to restart Latte"); qGuiApp->exit(); return 0; } if (parser.isSet(QStringLiteral("import-full"))) { bool imported = Latte::Importer::importHelper(parser.value(QStringLiteral("import-full"))); if (!imported) { qInfo() << i18n("The configuration cannot be imported"); qGuiApp->exit(); return 0; } } if (parser.isSet(QStringLiteral("import-layout"))) { QString importedLayout = Latte::Importer::importLayoutHelper(parser.value(QStringLiteral("import-layout"))); if (importedLayout.isEmpty()) { qInfo() << i18n("The layout cannot be imported"); qGuiApp->exit(); return 0; } else { layoutNameOnStartup = importedLayout; } } if (parser.isSet(QStringLiteral("multiple"))) { - memoryUsage = (int)(Latte::Dock::MultipleLayouts); + memoryUsage = (int)(Latte::Types::MultipleLayouts); } else if (parser.isSet(QStringLiteral("single"))) { - memoryUsage = (int)(Latte::Dock::SingleLayout); + memoryUsage = (int)(Latte::Types::SingleLayout); } if (parser.isSet(QStringLiteral("debug")) || parser.isSet(QStringLiteral("mask"))) { //! set pattern for debug messages //! [%{type}] [%{function}:%{line}] - %{message} [%{backtrace}] qSetMessagePattern(QStringLiteral( CIGREEN "[%{type} " CGREEN "%{time h:mm:ss.zz}" CIGREEN "]" CNORMAL #ifndef QT_NO_DEBUG CIRED " [" CCYAN "%{function}" CIRED ":" CCYAN "%{line}" CIRED "]" #endif CICYAN " - " CNORMAL "%{message}" CIRED "%{if-fatal}\n%{backtrace depth=8 separator=\"\n\"}%{endif}" "%{if-critical}\n%{backtrace depth=8 separator=\"\n\"}%{endif}" CNORMAL)); } else { const auto noMessageOutput = [](QtMsgType, const QMessageLogContext &, const QString &) {}; qInstallMessageHandler(noMessageOutput); } auto signal_handler = [](int) { qGuiApp->exit(); }; std::signal(SIGKILL, signal_handler); std::signal(SIGINT, signal_handler); KCrash::setDrKonqiEnabled(true); KCrash::setFlags(KCrash::AutoRestart | KCrash::AlwaysDirectly); Latte::Corona corona(defaultLayoutOnStartup, layoutNameOnStartup, memoryUsage); KDBusService service(KDBusService::Unique); return app.exec(); } inline void configureAboutData() { KAboutData about(QStringLiteral("lattedock") , QStringLiteral("Latte Dock") , QStringLiteral(VERSION) , i18n("Latte is a dock based on plasma frameworks that provides an elegant and " "intuitive experience for your tasks and plasmoids. It animates its contents " "by using parabolic zoom effect and tries to be there only when it is needed." "\n\n\"Art in Coffee\"") , KAboutLicense::GPL_V2 , QStringLiteral("\251 2016-2017 Michail Vourlakos, Smith AR")); about.setHomepage(WEBSITE); about.setBugAddress(BUG_ADDRESS); about.setProgramLogo(QIcon::fromTheme(QStringLiteral("latte-dock"))); about.setDesktopFileName(QStringLiteral("latte-dock")); // Authors about.addAuthor(QStringLiteral("Michail Vourlakos"), QString(), QStringLiteral("mvourlakos@gmail.com")); about.addAuthor(QStringLiteral("Smith AR"), QString(), QStringLiteral("audoban@openmailbox.org")); KAboutData::setApplicationData(about); } //! used the version provided by PW:KWorkspace inline void detectPlatform(int argc, char **argv) { if (qEnvironmentVariableIsSet("QT_QPA_PLATFORM")) { return; } for (int i = 0; i < argc; i++) { if (qstrcmp(argv[i], "-platform") == 0 || qstrcmp(argv[i], "--platform") == 0 || QByteArray(argv[i]).startsWith("-platform=") || QByteArray(argv[i]).startsWith("--platform=")) { return; } } const QByteArray sessionType = qgetenv("XDG_SESSION_TYPE"); if (sessionType.isEmpty()) { return; } if (qstrcmp(sessionType, "wayland") == 0) { qputenv("QT_QPA_PLATFORM", "wayland"); } else if (qstrcmp(sessionType, "x11") == 0) { qputenv("QT_QPA_PLATFORM", "xcb"); } } diff --git a/app/org.kde.latte-dock.appdata.xml.cmake b/app/org.kde.latte-dock.appdata.xml.cmake index c4cee37a..64d4900e 100644 --- a/app/org.kde.latte-dock.appdata.xml.cmake +++ b/app/org.kde.latte-dock.appdata.xml.cmake @@ -1,181 +1,181 @@ org.kde.latte-dock.desktop Latte لاتيه Latte Latte Latte Latte Latte Latte Latte Latte Latte Latte Latte Latte Latte Latte Latte Latte Latte Latte Latte Latte Latte Latte Латте xxLattexx Latte Latte Dock for the masses رصيف للأمور الكبيرة Dock per a les masses Dock per a les masses Dok pro masy Dok til masserne Dock für die Massen Πίνακες εφαρμογών για όλον τον κόσμο Dock for the masses Un dock para las masas Jendartearen kaia Telakka massoille Doca para as masas Dock untuk massa Area di aggancio per le masse 만인을 위한 독 Dock voor de massa Dokk for massane Dok dla mas Área acoplável para as massas Área acoplável para todos Док в массы Dok pre masy Dockningsfönster för alla Панель для усіх xxDock for the massesxx 给大众使用的停靠栏 給大眾使用的 Dock

Latte is a dock based on plasma frameworks that provides an elegant and intuitive experience for your tasks and plasmoids. It animates its contents by using parabolic zoom effect and tries to be there only when it is needed.

«لاتيه» هو رصيف مبنيّ على أُطر عمل «بلازما» حيث يقدّم تجربة أنيقة وبدهيّة لمهامك والبلازمويد لديك. يعمل الرّصيف على إنشاء حركة للمحتويات باستخدام تأثير تقريب القطع المكافئ، ويحاول أن يكون بمتناول يديك عند حاجتك إليه فقط.

El Latte és un acoblador basat en els Frameworks del Plasma que proporciona una experiència elegant i intuïtiva per a les vostres tasques i els plasmoides. Anima els seus continguts usant un efecte de zoom parabòlic i intenta mostrar-se només quan cal.

El Latte és un acoblador basat en els Frameworks del Plasma que proporciona una experiència elegant i intuïtiva per a les vostres tasques i els plasmoides. Anima els seus continguts usant un efecte de zoom parabòlic i intenta mostrar-se només quan cal.

Latte er en dok som er baseret på plasma-frameworks som giver en elegant og intuitiv oplevelse til dine opgaver og plasmoids. Den animerer dens indhold med parabolsk zoom og prøver på kun at være der når der er brug for det.

Latte-Dock ist ein auf Plasma-Framework-Technologie basierendes Dock für Anwendungen und Plasmoide, das ein elegantes und intuitives Nutzererlebnis bietet.Seine Inhalte werden mithilfe parabolischer Zoom-Effekte animiert. Latte versucht, immer zur Stelle zu sein, wenn es benötigt wird.

Το Latte είναι ένας πίνακας εφαρμογών βασισμένος στις βιβλιοθήκες plasma που εστιάζει στην καλαισθησία και παρέχει ένα όμορφο περιβάλλον για τις εργασίες και τα γραφικά συστατικά σας. Χρησιμοποιεί το παραβολικό εφέ έτσι ώστε να απεικονίσει τα περιεχόμενα του και προσπαθεί να είναι εκεί μόνο όταν το χρειάζεστε.

Latte is a dock based on plasma frameworks that provides an elegant and intuitive experience for your tasks and plasmoids. It animates its contents by using parabolic zoom effect and tries to be there only when it is needed.

Latte es un dock basado en la infraestructura plasma que proporciona una experiencia intuitiva y elegante para sus tareas y plasmoides. Anima sus contenidos usando un efecto de zoom parabólico e intenta estar presente solo cuando se le necesita.

Plasma frameworks-en oinarritutako kaia da Latte, bizipen eder eta intuitiboa hornitzen duena zure ataza eta aplikaziotxoentzat. Honek bere edukiak animatzen ditu zoom parabolikoaren efektua erabiliz eta bertan behar denean bakarrik egoten saiatzen da.

Latte on Plasma Frameworksiin perustuva telakka, joka tarjoaa tyylikkään ja intuitiivisen tehtävä- ja sovelmakäyttöliittymän. Se animoi sisältönsä parabolisella lähennystehosteella ja yrittää pysyä poissa, kunnes sitä tarvitaan.

Latte é unha doca construída coas infraestruturas de Plasma que fornece unha experiencia elegante e intuitiva para as súas tarefas e trebellos. Anima o seu contido usando o efecto de ampliación parabólico e intenta estar aí só cando se necesita.

Latte adalah dock berdasarkan kerangka kerja plasma yang memberikan pengalaman yang elegan dan intuitif untuk tugas dan plasmoid kamu. Ini menganimasikan isi dengan menggunakan efek zoom parabola dan mencoba untuk berada di sana hanya ketika diperlukan.

Latte è un'area di aggancio basata su plasma frameworks. Offre ai tuoi processi e ai tuoi plasmoidi un'esperienza elegante ed intuitiva, animando il loro contenuto con un effetto zoom parabolico e facendosi trovare solo quando necessario.

Latte는 작업과 Plasmoid를 우아하고 직관적으로 사용할 수 있는 Plasma 프레임워크 기반 독입니다. 포물선 크기 조정 효과 애니메이션을 사용하며 필요할 때만 표시됩니다.

Latte is een dock gebaseerd op plasma frameworks die een elegante en intuïtieve ervaring voor uw taken en plasmoids is. Het animeert zijn inhoud door een parabolisch zoomeffect te gebruiken en probeert er alleen te zijn wanneer nodig.

Latte er ein dokk basert på Plasma-rammeverket og som gjev elegant og intuitiv tilgang til program/oppgåver og skjermelement. Innhaldet vert animerte med parabolske forstørringseffektar og programmet prøver å ikkje vera i vegen når det ikkje trengst.

Latte jest dokiem opartym na szkieletach plazmy, który zapewnia przyjemne i intuicyjne odczucia w pracy z zadaniami i plazmoidami. Animuje swoją zawartośc przy użyciu efektu przybliżenia parabolicznego i próbuje być widocznym tylko wtedy, gdy jest potrzebny.

O Latte é uma área acoplável baseada nas plataformas do Plasma que oferece uma experiência elegante e intuitiva para as suas tarefas e plasmóides. Ele anima o seu conteúdo, usando um efeito de ampliação parabólico e tenta estar apenas onde for necessário.

O Latte é uma área acoplável baseada nos frameworks do Plasma que oferece uma experiência elegante e intuitiva para as suas tarefas e plasmoides. Ele anima o seu conteúdo, usando um efeito de zoom parabólico e tenta estar apenas onde for necessário.

Latte — это док-панель, основанная на KDE Frameworks, которая обеспечивает элегантный и интуитивно понятный интерфейс для задач и виджетов Plasma. Для анимация содержимого используется эффект параболического увеличения. Панель пытается быть видима только тогда, когда это необходимо.

Latte je dok založený na frameworkoch plasma, ktorý poskytuje elegantné a intuitívne rozhranie pre vaše úlohy a plazmoidy. Animuje svoj obsah použitím parabolického efektu priblíženia a snaží sa by tam len vtedy, keď je to treba.

Latte är ett dockningsfönster baserat på Plasma ramverk som erbjuder en elegant och intuitiv upplevelse för aktiviteter och Plasmoider. Det animerar innehållet genom att använda en paraboleffekt för zoomning, och försöker bara vara där när det behövs.

Латте — панель на основі бібліотек Плазми, яка забезпечує елегантний і інтуїтивно зрозумілий доступ до ваших завдань та плазмоїдів. Вміст панелі анімується за допомогою ефекту параболічного збільшення і показується лише тоді, коли це потрібно.

xxLatte is a dock based on plasma frameworks that provides an elegant and intuitive experience for your tasks and plasmoids. It animates its contents by using parabolic zoom effect and tries to be there only when it is needed.xx

Latte 是一个基于 plasma 框架的停靠栏,它为您的任务及 plasmoid 提供了优雅直观的体验。它为它的内容赋予抛物线缩放动画效果,并尽可能仅在它被需要时出现。

Latte 是一個基於 Plasma 框架並提供您的工作與 plasmoid 優雅與直觀體驗的 dock。它使用拋物線縮放效果來讓您的內容動畫化,並試著只在您需要它時出現。

"Art In Coffee"

”الفنّ في القهوة“

"Art al cafè"

"Art al cafè"

"Kunst i kaffe"

„Art In Coffee“

"Τέχνη στον Καφέ"

"Art In Coffee"

"El arte en el café"

"Artea kafean"

”Taidetta kahvissa”

«Arte en café».

"Art In Coffee"

«Art In Coffee»

"커피 예술"

"Kunst in koffie"

«Kunst i kaffi»

"Sztuka w Kawie"

"Art In Coffee"

"Arte no café"

«Искусство в кофе»

"Umenie v káve"

"Konst i kaffe"

«Мистецтво кави»

xx"Art In Coffee"xx

“咖啡中的艺术”

「咖啡中的藝術」

Utility KDE @WEBSITE@ @BUG_ADDRESS@ @FAQS@ Michail Vourlakos, Johan Smith Agudelo Rodriguez Michail Vourlakos, Johan Smith Agudelo Rodriguez Michail Vourlakos, Johan Smith Agudelo Rodriguez Michail Vourlakos, Johan Smith Agudelo Rodriguez Michail Vourlakos, Johan Smith Agudelo Rodriguez Michail Vourlakos, Johan Smith Agudelo Rodriguez Michail Vourlakos, Johan Smith Agudelo Rodriguez Michail Vourlakos, Johan Smith Agudelo Rodriguez Michail Vourlakos, Johan Smith Agudelo Rodriguez Michail Vourlakos, Johan Smith Agudelo Rodriguez Michail Vourlakos e Johan Smith Agudelo Rodriguez Michail Vourlakos, Johan Smith Agudelo Rodriguez Michail Vourlakos, Johan Smith Agudelo Rodriguez Michail Vourlakos, Johan Smith Agudelo Rodriguez Michail Vourlakos, Johan Smith Agudelo Rodriguez Michail Vourlakos, Johan Smith Agudelo Rodriguez Michail Vourlakos, Johan Smith Agudelo Rodriguez Michail Vourlakos, Johan Smith Agudelo Rodriguez Michail Vourlakos, Johan Smith Agudelo Rodriguez Michail Vourlakos, Johan Smith Agudelo Rodriguez Michail Vourlakos, Johan Smith Agudelo Rodriguez Michail Vourlakos, Johan Smith Agudelo Rodriguez Michail Vourlakos, Johan Smith Agudelo Rodriguez xxMichail Vourlakos, Johan Smith Agudelo Rodriguezxx Michail Vourlakos, Johan Smith Agudelo Rodriguez Michail Vourlakos, Johan Smith Agudelo Rodriguez latte-dock GPL v2+ CC0-1.0 https://cdn.kde.org/screenshots/latte-dock/latte-dock_regular.png https://cdn.kde.org/screenshots/latte-dock/latte-dock_badges.png https://cdn.kde.org/screenshots/latte-dock/latte-dock_settings.png https://cdn.kde.org/screenshots/latte-dock/latte-dock_settings2.png https://cdn.kde.org/screenshots/latte-dock/latte-dock_toppanel.png KDE latte-dock - liblattedockplugin.so + liblatte2plugin.so
diff --git a/app/settings/settingsdialog.cpp b/app/settings/settingsdialog.cpp index 51adec89..cb406dee 100644 --- a/app/settings/settingsdialog.cpp +++ b/app/settings/settingsdialog.cpp @@ -1,1605 +1,1605 @@ /* * 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 "layout.h" #include "layoutmanager.h" #include "importer.h" #include "plasmathemeextended.h" #include "universalsettings.h" #include "ui_settingsdialog.h" #include "../lattecorona.h" -#include "../liblattedock/dock.h" +#include "../liblatte2/types.h" #include "delegates/checkboxdelegate.h" #include "delegates/colorcmbboxdelegate.h" #include "delegates/activitycmbboxdelegate.h" #include "delegates/layoutnamedelegate.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 SCREENTRACKERDEFAULTVALUE = 2500; const int THEMEDEFAULTROUNDNESS = 0; //Breeze default value is used 0px. 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->layoutManager()->layouts().count(), 6, this); ui->layoutsView->setModel(m_model); ui->layoutsView->horizontalHeader()->setStretchLastSection(true); ui->layoutsView->verticalHeader()->setVisible(false); connect(m_corona->layoutManager(), &LayoutManager::currentLayoutNameChanged, this, &SettingsDialog::layoutsChanged); connect(m_corona->layoutManager(), &LayoutManager::activeLayoutsChanged, 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; foreach (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 ActivityCmbBoxDelegate(this)); m_inMemoryButtons = new QButtonGroup(this); - m_inMemoryButtons->addButton(ui->singleToolBtn, Latte::Dock::SingleLayout); - m_inMemoryButtons->addButton(ui->multipleToolBtn, Latte::Dock::MultipleLayouts); + 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::Dock::MultipleLayouts)->setEnabled(false); + m_inMemoryButtons->button(Latte::Types::MultipleLayouts)->setEnabled(false); } m_mouseSensitivityButtons = new QButtonGroup(this); - m_mouseSensitivityButtons->addButton(ui->lowSensitivityBtn, Latte::Dock::LowSensitivity); - m_mouseSensitivityButtons->addButton(ui->mediumSensitivityBtn, Latte::Dock::MediumSensitivity); - m_mouseSensitivityButtons->addButton(ui->highSensitivityBtn, Latte::Dock::HighSensitivity); + 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->themeRoundnessSpinBox->setValue(m_corona->themeExtended()->userThemeRoundness()); //! 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 *helpMenu = new QMenu(i18n("Help"), menuBar); //rightAlignedMenuBar->addMenu(helpMenu); menuBar->addMenu(helpMenu); QAction *quitAction = fileMenu->addAction(i18n("Quit Latte")); quitAction->setIcon(QIcon::fromTheme("application-exit")); quitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q)); 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(); }); connect(m_mouseSensitivityButtons, static_cast(&QButtonGroup::buttonToggled), [ = ](int id, bool checked) { updateApplyButtonsState(); }); connect(ui->screenTrackerSpinBox, QOverload::of(&QSpinBox::valueChanged), [ = ](int i) { updateApplyButtonsState(); }); connect(ui->themeRoundnessSpinBox, QOverload::of(&QSpinBox::valueChanged), [ = ](int i) { updateApplyButtonsState(); }); connect(ui->autostartChkBox, &QCheckBox::stateChanged, this, &SettingsDialog::updateApplyButtonsState); connect(ui->metaChkBox, &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, m_corona, &Latte::Corona::closeApplication); //! 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)); m_corona->universalSettings()->setLayoutsColumnWidths(columnWidths); } m_inMemoryButtons->deleteLater(); m_mouseSensitivityButtons->deleteLater(); foreach (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->layoutManager()->activities(); } QStringList SettingsDialog::availableActivities() { return m_availableActivities; } -void SettingsDialog::setCurrentPage(Dock::LatteConfigPage page) +void SettingsDialog::setCurrentPage(Types::LatteConfigPage page) { - if (page == Dock::LayoutPage) { + if (page == Types::LayoutPage) { ui->tabWidget->setCurrentIndex(0); - } else if (page == Dock::PreferencesPage) { + } else if (page == Types::PreferencesPage) { ui->tabWidget->setCurrentIndex(1); } } void SettingsDialog::on_newButton_clicked() { qDebug() << Q_FUNC_INFO; //! find Default preset path foreach (auto preset, m_corona->layoutManager()->presetsPaths()) { QString presetName = Layout::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->layoutManager()->memoryUsage() == Dock::MultipleLayouts) { + if (m_corona->layoutManager()->memoryUsage() == Types::MultipleLayouts) { QString lName = (m_model->data(m_model->index(row, NAMECOLUMN), Qt::DisplayRole)).toString(); if (Importer::layoutExists(lName)) { Layout *layout = m_corona->layoutManager()->activeLayout(lName); if (layout && layout->isOriginalLayout()) { layout->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); } Layout *settings = new Layout(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()) { foreach (auto entry, dialog.installedEntries()) { foreach (auto entryFile, entry.installedFiles()) { Importer::LatteFileVersion version = Importer::fileVersion(entryFile); if (version == 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->layoutManager()->activeLayout(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_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) { Importer::LatteFileVersion version = Importer::fileVersion(file); qDebug() << "VERSION :::: " << version; if (version == Importer::LayoutVersion2) { addLayoutForFile(file); } else if (version == 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 == 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(); foreach (auto &name, archiveRootDir->entries()) { auto fileEntry = archiveRootDir->file(name); fileEntry->copyTo(tempDir.absolutePath()); } QString name = Importer::nameOfConfigFile(file); QString applets(tempDir.absolutePath() + "/" + "lattedock-appletsrc"); if (QFile(applets).exists()) { if (m_corona->layoutManager()->importer()->importOldLayout(applets, name, false, tempDir.absolutePath())) { addLayoutForFile(tempDir.absolutePath() + "/" + name + ".layout.latte", name, false); } QString alternativeName = name + "-" + i18nc("layout", "Alternative"); if (m_corona->layoutManager()->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->layoutManager()->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); } Layout 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->layoutManager()->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 foreach (auto preset, m_corona->layoutManager()->presetsPaths()) { QString presetName = Layout::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->infoWindowChkBox->setChecked(true); ui->metaChkBox->setChecked(false); ui->noBordersForMaximizedChkBox->setChecked(false); ui->highSensitivityBtn->setChecked(true); ui->screenTrackerSpinBox->setValue(SCREENTRACKERDEFAULTVALUE); ui->themeRoundnessSpinBox->setValue(THEMEDEFAULTROUNDNESS); } } void SettingsDialog::addLayoutForFile(QString file, QString layoutName, bool newTempDirectory, bool showNotification) { if (layoutName.isEmpty()) { layoutName = Layout::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)) { Layout *oldSettings = m_layouts.take(copiedId); delete oldSettings; } Layout *settings = new Layout(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(); int i = 0; QStringList brokenLayouts; - if (m_corona->layoutManager()->memoryUsage() == Dock::MultipleLayouts) { + if (m_corona->layoutManager()->memoryUsage() == Types::MultipleLayouts) { m_corona->layoutManager()->syncActiveLayoutsToOriginalFiles(); } foreach (auto layout, m_corona->layoutManager()->layouts()) { QString layoutPath = QDir::homePath() + "/.config/latte/" + layout + ".layout.latte"; m_initLayoutPaths.append(layoutPath); Layout *layoutSets = new Layout(this, layoutPath); m_layouts[layoutPath] = layoutSets; QString background = layoutSets->background(); if (background.isEmpty()) { insertLayoutInfoAtRow(i, layoutPath, layoutSets->color(), QString(), layoutSets->name(), layoutSets->showInMenu(), layoutSets->disableBordersForMaximizedWindows(), layoutSets->activities(), !layoutSets->isWritable()); } else { insertLayoutInfoAtRow(i, layoutPath, background, layoutSets->textColor(), layoutSets->name(), layoutSets->showInMenu(), layoutSets->disableBordersForMaximizedWindows(), layoutSets->activities(), !layoutSets->isWritable()); } qDebug() << "counter:" << i << " total:" << m_model->rowCount(); i++; if (layoutSets->name() == m_corona->layoutManager()->currentLayoutName()) { ui->layoutsView->selectRow(i - 1); } Layout *activeLayout = m_corona->layoutManager()->activeLayout(layoutSets->name()); if ((activeLayout && activeLayout->layoutIsBroken()) || (!activeLayout && layoutSets->layoutIsBroken())) { brokenLayouts.append(layoutSets->name()); } } //! Check Multiple Layouts Integrity - /*if (m_corona->layoutManager()->memoryUsage() == Dock::MultipleLayouts) { + /*if (m_corona->layoutManager()->memoryUsage() == Types::MultipleLayouts) { m_corona->layoutManager()->syncActiveLayoutsToOriginalFiles(); QString multipleLayoutPath = QDir::homePath() + "/.config/latte/" + Layout::MultipleLayoutsName + ".layout.latte"; Layout multipleHiddenLayouts(this, multipleLayoutPath, "Multiple Layouts File"); if (multipleHiddenLayouts.layoutIsBroken()) { qDebug() << "Intergrity Error ::: Multiple Layouts Hidden file is broken!!!!"; brokenLayouts.append(multipleHiddenLayouts.name()); } }*/ recalculateAvailableActivities(); m_model->setHorizontalHeaderItem(IDCOLUMN, new QStandardItem(QString("#path"))); m_model->setHorizontalHeaderItem(COLORCOLUMN, new QStandardItem(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(QString(i18nc("column for layout to show which activities is assigned to", "Activities")))); //! 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() && columnWidths.count() == 4) { ui->layoutsView->setColumnWidth(COLORCOLUMN, columnWidths[0].toInt()); ui->layoutsView->setColumnWidth(NAMECOLUMN, columnWidths[1].toInt()); ui->layoutsView->setColumnWidth(MENUCOLUMN, columnWidths[2].toInt()); ui->layoutsView->setColumnWidth(BORDERSCOLUMN, columnWidths[3].toInt()); } - if (m_corona->layoutManager()->memoryUsage() == Dock::SingleLayout) { + if (m_corona->layoutManager()->memoryUsage() == Types::SingleLayout) { ui->singleToolBtn->setChecked(true); - } else if (m_corona->layoutManager()->memoryUsage() == Dock::MultipleLayouts) { + } else if (m_corona->layoutManager()->memoryUsage() == Types::MultipleLayouts) { ui->multipleToolBtn->setChecked(true); } updatePerLayoutButtonsState(); ui->autostartChkBox->setChecked(m_corona->universalSettings()->autostart()); ui->infoWindowChkBox->setChecked(m_corona->universalSettings()->showInfoWindow()); ui->metaChkBox->setChecked(m_corona->universalSettings()->metaForwardedToLatte()); ui->noBordersForMaximizedChkBox->setChecked(m_corona->universalSettings()->canDisableBorders()); - if (m_corona->universalSettings()->mouseSensitivity() == Dock::LowSensitivity) { + if (m_corona->universalSettings()->mouseSensitivity() == Types::LowSensitivity) { ui->lowSensitivityBtn->setChecked(true); - } else if (m_corona->universalSettings()->mouseSensitivity() == Dock::MediumSensitivity) { + } else if (m_corona->universalSettings()->mouseSensitivity() == Types::MediumSensitivity) { ui->mediumSensitivityBtn->setChecked(true); - } else if (m_corona->universalSettings()->mouseSensitivity() == Dock::HighSensitivity) { + } else if (m_corona->universalSettings()->mouseSensitivity() == Types::HighSensitivity) { ui->highSensitivityBtn->setChecked(true); } o_settings = currentSettings(); o_settingsLayouts = currentLayoutsSettings(); updateApplyButtonsState(); //! 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->infoWindowChkBox->isChecked(); settings << (int)ui->metaChkBox->isChecked(); settings << (int)ui->noBordersForMaximizedChkBox->isChecked(); settings << m_mouseSensitivityButtons->checkedId(); settings << ui->screenTrackerSpinBox->value(); settings << ui->themeRoundnessSpinBox->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(); 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; } 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(",")); QList items; items.append(pathItem); items.append(hiddenTextItem); items.append(colorItem); items.append(nameItem); items.append(menuItem); items.append(bordersItem); items.append(activitiesItem); 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->layoutManager()->activeLayout(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::Dock::MultipleLayouts) { + 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->layoutManager()->switchToLayout(lName); } } else { QVariant value = m_model->data(m_model->index(ui->layoutsView->currentIndex().row(), NAMECOLUMN), Qt::DisplayRole); if (value.isValid()) { m_corona->layoutManager()->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(); Layout *layout = m_layouts[id]; if (layout) { m_corona->layoutManager()->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->layoutManager()->currentLayoutName() == name) { font.setBold(true); // ui->layoutsView->selectRow(i); } else { Layout *layout = m_corona->layoutManager()->activeLayout(name); - if (layout && (m_corona->layoutManager()->memoryUsage() == Dock::MultipleLayouts)) { + if (layout && (m_corona->layoutManager()->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_layouts[id]->name() != name) { font.setItalic(true); m_model->setData(m_model->index(currentRow, NAMECOLUMN), font, Qt::FontRole); } else { font.setItalic(false); m_model->setData(m_model->index(currentRow, NAMECOLUMN), font, Qt::FontRole); } } 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}; foreach (auto preset, m_corona->layoutManager()->presetsPaths()) { QString presetName = Layout::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->metaChkBox->isChecked() || !ui->infoWindowChkBox->isChecked() || ui->noBordersForMaximizedChkBox->isChecked() || !ui->highSensitivityBtn->isChecked() || ui->screenTrackerSpinBox->value() != SCREENTRACKERDEFAULTVALUE || ui->themeRoundnessSpinBox->value() != THEMEDEFAULTROUNDNESS) { 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(); //! Switch Button if (id.startsWith("/tmp/") || originalName != nameInModel) { ui->switchButton->setEnabled(false); } else { ui->switchButton->setEnabled(true); } //! Pause Button - if (m_corona->layoutManager()->memoryUsage() == Dock::SingleLayout) { + if (m_corona->layoutManager()->memoryUsage() == Types::SingleLayout) { ui->pauseButton->setVisible(false); - } else if (m_corona->layoutManager()->memoryUsage() == Dock::MultipleLayouts) { + } else if (m_corona->layoutManager()->memoryUsage() == Types::MultipleLayouts) { ui->pauseButton->setVisible(true); QStringList lActivities = m_model->data(m_model->index(currentRow, ACTIVITYCOLUMN), Qt::UserRole).toStringList(); Layout *layout = m_layouts[id]; if (!lActivities.isEmpty() && layout && m_corona->layoutManager()->activeLayout(layout->name())) { ui->pauseButton->setEnabled(true); } else { ui->pauseButton->setEnabled(false); } } //! Remove Layout Button if (originalName != nameInModel || (originalName == m_corona->layoutManager()->currentLayoutName()) || (m_corona->layoutManager()->activeLayout(originalName)) || lockedInModel) { ui->removeButton->setEnabled(false); } else { ui->removeButton->setEnabled(true); } if (lockedInModel) { ui->lockedButton->setChecked(true); } else { ui->lockedButton->setChecked(false); } } void SettingsDialog::recalculateAvailableActivities() { QStringList tempActivities = m_corona->layoutManager()->activities(); for (int i = 0; i < m_model->rowCount(); ++i) { QStringList assigned = m_model->data(m_model->index(i, ACTIVITYCOLUMN), Qt::UserRole).toStringList(); foreach (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; } bool SettingsDialog::saveAllChanges() { if (!dataAreAccepted()) { return false; } //! Update universal settings - Latte::Dock::MouseSensitivity sensitivity = static_cast(m_mouseSensitivityButtons->checkedId()); + Latte::Types::MouseSensitivity sensitivity = static_cast(m_mouseSensitivityButtons->checkedId()); bool autostart = ui->autostartChkBox->isChecked(); bool forwardMeta = ui->metaChkBox->isChecked(); bool showInfoWindow = ui->infoWindowChkBox->isChecked(); bool noBordersForMaximized = ui->noBordersForMaximizedChkBox->isChecked(); m_corona->universalSettings()->setMouseSensitivity(sensitivity); m_corona->universalSettings()->setAutostart(autostart); m_corona->universalSettings()->forwardMetaToLatte(forwardMeta); m_corona->universalSettings()->setShowInfoWindow(showInfoWindow); m_corona->universalSettings()->setCanDisableBorders(noBordersForMaximized); m_corona->universalSettings()->setScreenTrackerInterval(ui->screenTrackerSpinBox->value()); m_corona->themeExtended()->setUserThemeRoundness(ui->themeRoundnessSpinBox->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 foreach (auto initLayout, m_initLayoutPaths) { if (!idExistsInModel(initLayout)) { QFile(initLayout).remove(); if (m_layouts.contains(initLayout)) { Layout *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 foreach (auto activity, lActivities) { if (knownActivities.contains(activity)) { cleanedActivities.append(activity); } } //qDebug() << i << ". " << id << " - " << color << " - " << name << " - " << menu << " - " << lActivities; Layout *activeLayout = m_corona->layoutManager()->activeLayout(m_layouts[id]->name()); Layout *layout = activeLayout ? activeLayout : m_layouts[id]; //! unlock read-only layout if (!layout->isWritable()) { layout->unlock(); } if (color.startsWith("/")) { //it is image file in such case if (color != layout->background()) { layout->setBackground(color); } if (layout->textColor() != textColor) { layout->setTextColor(textColor); } } else { if (color != layout->color()) { layout->setColor(color); layout->setBackground(QString()); layout->setTextColor(QString()); } } if (layout->showInMenu() != menu) { layout->setShowInMenu(menu); } if (layout->disableBordersForMaximizedWindows() != disabledBorders) { layout->setDisableBordersForMaximizedWindows(disabledBorders); } if (layout->activities() != cleanedActivities) { layout->setActivities(cleanedActivities); } //! If the layout name changed OR the layout path is a temporary one if (layout->name() != name || (id.startsWith("/tmp/"))) { //! If the layout is Active in MultipleLayouts - if (m_corona->layoutManager()->memoryUsage() == Dock::MultipleLayouts && activeLayout) { + if (m_corona->layoutManager()->memoryUsage() == Types::MultipleLayouts && activeLayout) { qDebug() << " Active Layout Should Be Renamed From : " << layout->name() << " TO :: " << name; activeLayoutsToRename[name] = layout; } QString tempFile = layoutTempDir.path() + "/" + QString(layout->name() + ".layout.latte"); qDebug() << "new temp file ::: " << tempFile; - if ((m_corona->layoutManager()->memoryUsage() == Dock::SingleLayout) && (layout->name() == m_corona->layoutManager()->currentLayoutName())) { + if ((m_corona->layoutManager()->memoryUsage() == Types::SingleLayout) && (layout->name() == m_corona->layoutManager()->currentLayoutName())) { switchToLayout = name; } layout = m_layouts.take(id); delete layout; 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); Layout *nLayout = new Layout(this, newFile); m_layouts[newFile] = nLayout; 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->layoutManager()->memoryUsage() == Dock::MultipleLayouts) { + if (m_corona->layoutManager()->memoryUsage() == Types::MultipleLayouts) { foreach (auto newLayoutName, activeLayoutsToRename.keys()) { qDebug() << " Active Layout Is Renamed From : " << activeLayoutsToRename[newLayoutName]->name() << " TO :: " << newLayoutName; Layout *layout = activeLayoutsToRename[newLayoutName]; layout->renameLayout(newLayoutName); //! that means it is an active layout for orphaned Activities if (layout->activities().isEmpty()) { orphanedLayout = newLayoutName; } } } //! 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 *activeLayout = m_corona->layoutManager()->activeLayout(m_layouts[id]->name()); Layout *layout = activeLayout ? activeLayout : m_layouts[id]; if (layout && locked && layout->isWritable()) { layout->lock(); } } m_corona->layoutManager()->loadLayouts(); - Latte::Dock::LayoutsMemoryUsage inMemoryOption = static_cast(m_inMemoryButtons->checkedId()); + Latte::Types::LayoutsMemoryUsage inMemoryOption = static_cast(m_inMemoryButtons->checkedId()); if (m_corona->layoutManager()->memoryUsage() != inMemoryOption) { - Dock::LayoutsMemoryUsage previousMemoryUsage = m_corona->layoutManager()->memoryUsage(); + Types::LayoutsMemoryUsage previousMemoryUsage = m_corona->layoutManager()->memoryUsage(); m_corona->layoutManager()->setMemoryUsage(inMemoryOption); QVariant value = m_model->data(m_model->index(ui->layoutsView->currentIndex().row(), NAMECOLUMN), Qt::DisplayRole); QString layoutName = value.toString(); m_corona->layoutManager()->switchToLayout(layoutName, previousMemoryUsage); } else { if (!switchToLayout.isEmpty()) { m_corona->layoutManager()->switchToLayout(switchToLayout); - } else if (m_corona->layoutManager()->memoryUsage() == Dock::MultipleLayouts) { + } else if (m_corona->layoutManager()->memoryUsage() == Types::MultipleLayouts) { m_corona->layoutManager()->syncMultipleLayoutsToActivities(orphanedLayout); } } return true; } 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; } 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(); } 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/settingsdialog.h b/app/settings/settingsdialog.h index 3cbc3138..3b07694c 100644 --- a/app/settings/settingsdialog.h +++ b/app/settings/settingsdialog.h @@ -1,138 +1,138 @@ /* * 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 SETTINGSDIALOG_H #define SETTINGSDIALOG_H // local -#include "../liblattedock/dock.h" +#include "../liblatte2/types.h" // Qt #include #include #include #include #include #include namespace Ui { class SettingsDialog; } namespace KActivities { class Controller; } namespace Latte { class Corona; class Layout; } namespace Latte { class SettingsDialog : public QDialog { Q_OBJECT public: SettingsDialog(QWidget *parent, Latte::Corona *corona); ~SettingsDialog(); - void setCurrentPage(Dock::LatteConfigPage page); + void setCurrentPage(Types::LatteConfigPage page); QStringList activities(); QStringList availableActivities(); void requestImagesDialog(int row); void requestColorsDialog(int row); private slots: // auto connections void on_newButton_clicked(); void on_copyButton_clicked(); void on_downloadButton_clicked(); void on_lockedButton_clicked(); void on_pauseButton_clicked(); void on_removeButton_clicked(); void on_switchButton_clicked(); void on_importButton_clicked(); void on_exportButton_clicked(); void accept() override; void reject() override; void apply(); void restoreDefaults(); void updatePerLayoutButtonsState(); void layoutsChanged(); void itemChanged(QStandardItem *item); private: void addLayoutForFile(QString file, QString layoutName = QString(), bool newTempDirectory = true, bool showNotification = true); //! When an activity is closed for some reason the window manager hides and reshows //! the windows. This function prevents this because we don't want to delete the window //! on reject in such case. void blockDeleteOnActivityStopped(); void loadSettings(); void recalculateAvailableActivities(); void insertLayoutInfoAtRow(int row, QString path, QString color, QString textColor, QString name, bool menu, bool disabledBorders, QStringList activities, bool locked = false); void updateApplyButtonsState(); bool dataAreAccepted(); bool idExistsInModel(QString id); bool importLayoutsFromV1ConfigFile(QString file); bool nameExistsInModel(QString name); bool saveAllChanges(); int ascendingRowFor(QString name); QString uniqueTempDirectory(); QString uniqueLayoutName(QString name); QList currentSettings(); QStringList currentLayoutsSettings(); private: QStringList m_availableActivities; QStringList m_tempDirectories; QStringList m_initLayoutPaths; QButtonGroup *m_inMemoryButtons; QButtonGroup *m_mouseSensitivityButtons; QTimer m_activityClosedTimer; bool m_blockDeleteOnReject{false}; Latte::Corona *m_corona{nullptr}; QStandardItemModel *m_model{nullptr}; Ui::SettingsDialog *ui; QHash m_layouts; QList o_settings; QStringList o_settingsLayouts; }; } #endif // SETTINGSDIALOG_H diff --git a/app/settings/universalsettings.cpp b/app/settings/universalsettings.cpp index af3450c3..d360396e 100644 --- a/app/settings/universalsettings.cpp +++ b/app/settings/universalsettings.cpp @@ -1,561 +1,561 @@ /* * 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 "layoutmanager.h" #include "sortedactivitiesmodel.h" // Qt #include #include #include // KDE #include #include #define GLOBALSHORTCUTSCONFIG "kglobalshortcutsrc" #define KWINMETAFORWARDTOLATTESTRING "org.kde.lattedock,/Latte,org.kde.LatteDock,activateLauncherMenu" #define KWINMETAFORWARDTOPLASMASTRING "org.kde.plasmashell,/PlasmaShell,org.kde.PlasmaShell,activateLauncherMenu" 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::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::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); } UniversalSettings::~UniversalSettings() { saveConfig(); cleanupSettings(); if (m_runningActivitiesModel) { m_runningActivitiesModel->deleteLater(); } } void UniversalSettings::initGlobalShortcutsWatcher() { const QString globalShortcutsFilePath = QDir::homePath() + "/.config/" + GLOBALSHORTCUTSCONFIG; m_shortcutsConfigPtr = KSharedConfig::openConfig(globalShortcutsFilePath); KDirWatch::self()->addFile(globalShortcutsFilePath); connect(KDirWatch::self(), &KDirWatch::dirty, this, &UniversalSettings::shortcutsFileChanged, Qt::QueuedConnection); connect(KDirWatch::self(), &KDirWatch::created, this, &UniversalSettings::shortcutsFileChanged, Qt::QueuedConnection); } void UniversalSettings::shortcutsFileChanged(const QString &file) { if (!file.endsWith(GLOBALSHORTCUTSCONFIG)) { return; } m_shortcutsConfigPtr->reparseConfiguration(); parseGlobalShortcuts(); } void UniversalSettings::parseGlobalShortcuts() { KConfigGroup latteGroup = KConfigGroup(m_shortcutsConfigPtr, "lattedock"); //! make sure that latte dock records in global shortcuts where found correctly bool recordsExist{true}; if (!latteGroup.exists()) { recordsExist = false; } if (recordsExist) { for (int i = 1; i <= 19; ++i) { QString entry = "activate entry " + QString::number(i); if (!latteGroup.hasKey(entry)) { recordsExist = false; break; } } } if (recordsExist) { m_badgesForActivate.clear(); for (int i = 1; i <= 19; ++i) { QString entry = "activate entry " + QString::number(i); QStringList records = latteGroup.readEntry(entry, QStringList()); QString badge; if (records[0] != "none") { QStringList modifiers = records[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(); } } } m_badgesForActivate << badge; } emit badgesForActivateChanged(); qDebug() << "badges updated to :: " << m_badgesForActivate; } } void UniversalSettings::load() { //! check if user has set the autostart option bool autostartUserSet = m_universalGroup.readEntry("userConfiguredAutostart", false); if (!autostartUserSet && !autostart()) { setAutostart(true); } //! load configuration loadConfig(); //! connections with other classes connect(m_corona->layoutManager(), &LayoutManager::viewColorizerChanged, this, &UniversalSettings::reconsiderActivitiesModel); //! load global shortcuts badges at startup initGlobalShortcutsWatcher(); parseGlobalShortcuts(); } 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::badgesForActivate() const { return m_badgesForActivate; } 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("/usr/share/applications/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()) { metaFile.copy(autostartFile.fileName()); //! I havent 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::canDisableBorders() const { return m_canDisableBorders; } void UniversalSettings::setCanDisableBorders(bool enable) { if (m_canDisableBorders == enable) { return; } m_canDisableBorders = enable; emit canDisableBordersChanged(); } bool UniversalSettings::metaForwardedToLatte() const { return kwin_metaForwardedToLatte(); } void UniversalSettings::forwardMetaToLatte(bool forward) { kwin_forwardMetaToLatte(forward); } bool UniversalSettings::kwin_metaForwardedToLatte() 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); } void UniversalSettings::kwin_forwardMetaToLatte(bool forward) { if (kwin_metaForwardedToLatte() == 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"); } } -Dock::LayoutsMemoryUsage UniversalSettings::layoutsMemoryUsage() const +Types::LayoutsMemoryUsage UniversalSettings::layoutsMemoryUsage() const { return m_memoryUsage; } -void UniversalSettings::setLayoutsMemoryUsage(Dock::LayoutsMemoryUsage layoutsMemoryUsage) +void UniversalSettings::setLayoutsMemoryUsage(Types::LayoutsMemoryUsage layoutsMemoryUsage) { if (m_memoryUsage == layoutsMemoryUsage) { return; } m_memoryUsage = layoutsMemoryUsage; emit layoutsMemoryUsageChanged(); } -Dock::MouseSensitivity UniversalSettings::mouseSensitivity() const +Types::MouseSensitivity UniversalSettings::mouseSensitivity() const { return m_mouseSensitivity; } -void UniversalSettings::setMouseSensitivity(Dock::MouseSensitivity sensitivity) +void UniversalSettings::setMouseSensitivity(Types::MouseSensitivity sensitivity) { if (m_mouseSensitivity == sensitivity) { return; } m_mouseSensitivity = sensitivity; emit mouseSensitivityChanged(); } void UniversalSettings::loadConfig() { m_version = m_universalGroup.readEntry("version", 1); 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_screenTrackerInterval = m_universalGroup.readEntry("screenTrackerInterval", 2500); m_showInfoWindow = m_universalGroup.readEntry("showInfoWindow", true); - m_memoryUsage = static_cast(m_universalGroup.readEntry("memoryUsage", (int)Dock::SingleLayout)); - m_mouseSensitivity = static_cast(m_universalGroup.readEntry("mouseSensitivity", (int)Dock::HighSensitivity)); + m_memoryUsage = static_cast(m_universalGroup.readEntry("memoryUsage", (int)Types::SingleLayout)); + m_mouseSensitivity = static_cast(m_universalGroup.readEntry("mouseSensitivity", (int)Types::HighSensitivity)); } void UniversalSettings::saveConfig() { m_universalGroup.writeEntry("version", m_version); 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("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"); } QAbstractItemModel *UniversalSettings::runningActivitiesModel() const { return m_runningActivitiesModel; } void UniversalSettings::setRunningActivitiesModel(SortedActivitiesModel *model) { if (m_runningActivitiesModel == model) { return; } if (m_runningActivitiesModel) { m_runningActivitiesModel->deleteLater(); } m_runningActivitiesModel = model; emit runningActivitiesModelChanged(); } void UniversalSettings::enableActivitiesModel() { if (!m_runningActivitiesModel) { setRunningActivitiesModel(new SortedActivitiesModel({KActivities::Info::Running, KActivities::Info::Stopping}, this)); } } void UniversalSettings::disableActivitiesModel() { if (m_runningActivitiesModel) { setRunningActivitiesModel(nullptr); } } void UniversalSettings::reconsiderActivitiesModel() { if (m_corona->layoutManager()->hasColorizer()) { enableActivitiesModel(); } else { disableActivitiesModel(); } } float UniversalSettings::luminasFromFile(QString imageFile, int edge) { enableActivitiesModel(); return m_runningActivitiesModel->luminasFromFile(imageFile, edge); } 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); } } diff --git a/app/settings/universalsettings.h b/app/settings/universalsettings.h index 5dad4047..8a8b0959 100644 --- a/app/settings/universalsettings.h +++ b/app/settings/universalsettings.h @@ -1,198 +1,198 @@ /* * 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 "../liblattedock/dock.h" +#include "../liblatte2/types.h" // Qt #include #include #include #include #include // KDE #include #include class SortedActivitiesModel; namespace Latte { class LayoutManager; //! 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 showInfoWindow READ showInfoWindow WRITE setShowInfoWindow NOTIFY showInfoWindowChanged) Q_PROPERTY(QString currentLayoutName READ currentLayoutName WRITE setCurrentLayoutName NOTIFY currentLayoutNameChanged) Q_PROPERTY(QStringList badgesForActivate READ badgesForActivate NOTIFY badgesForActivateChanged) Q_PROPERTY(QStringList launchers READ launchers WRITE setLaunchers NOTIFY launchersChanged) - Q_PROPERTY(Latte::Dock::MouseSensitivity mouseSensitivity READ mouseSensitivity WRITE setMouseSensitivity NOTIFY mouseSensitivityChanged) + Q_PROPERTY(Latte::Types::MouseSensitivity mouseSensitivity READ mouseSensitivity WRITE setMouseSensitivity NOTIFY mouseSensitivityChanged) Q_PROPERTY(QAbstractItemModel *runningActivitiesModel READ runningActivitiesModel NOTIFY runningActivitiesModelChanged) 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 canDisableBorders() const; void setCanDisableBorders(bool enable); bool metaForwardedToLatte() const; void forwardMetaToLatte(bool forward); 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 badgesForActivate() const; QStringList layoutsColumnWidths() const; void setLayoutsColumnWidths(QStringList widths); QStringList launchers() const; void setLaunchers(QStringList launcherList); - Dock::MouseSensitivity mouseSensitivity() const; - void setMouseSensitivity(Dock::MouseSensitivity sensitivity); + Types::MouseSensitivity mouseSensitivity() const; + void setMouseSensitivity(Types::MouseSensitivity sensitivity); QAbstractItemModel *runningActivitiesModel() const; void setRunningActivitiesModel(SortedActivitiesModel *model); 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 luminasFromFile(QString imageFile, int edge); signals: void autostartChanged(); void badgesForActivateChanged(); void canDisableBordersChanged(); void currentLayoutNameChanged(); void downloadWindowSizeChanged(); void lastNonAssignedLayoutNameChanged(); void layoutsColumnWidthsChanged(); void layoutsWindowSizeChanged(); void launchersChanged(); void layoutsMemoryUsageChanged(); void mouseSensitivityChanged(); void runningActivitiesModelChanged(); void screenTrackerIntervalChanged(); void showInfoWindowChanged(); void versionChanged(); private slots: void loadConfig(); void saveConfig(); void reconsiderActivitiesModel(); void shortcutsFileChanged(const QString &file); private: void cleanupSettings(); void enableActivitiesModel(); void disableActivitiesModel(); void initGlobalShortcutsWatcher(); //! access user set global shortcuts for activate entries void parseGlobalShortcuts(); bool kwin_metaForwardedToLatte() const; void kwin_forwardMetaToLatte(bool forward); - Dock::LayoutsMemoryUsage layoutsMemoryUsage() const; - void setLayoutsMemoryUsage(Dock::LayoutsMemoryUsage layoutsMemoryUsage); + Types::LayoutsMemoryUsage layoutsMemoryUsage() const; + void setLayoutsMemoryUsage(Types::LayoutsMemoryUsage layoutsMemoryUsage); private: bool m_canDisableBorders{false}; bool m_showInfoWindow{true}; //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_badgesForActivate{"1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "z", "x", "c", "v", "b", "n", "m", ",", "."}; QStringList m_layoutsColumnWidths; QStringList m_launchers; - Dock::LayoutsMemoryUsage m_memoryUsage; - Dock::MouseSensitivity m_mouseSensitivity{Dock::HighSensitivity}; + Types::LayoutsMemoryUsage m_memoryUsage; + Types::MouseSensitivity m_mouseSensitivity{Types::HighSensitivity}; SortedActivitiesModel *m_runningActivitiesModel{nullptr}; QPointer m_corona; KConfigGroup m_universalGroup; KSharedConfig::Ptr m_config; KSharedConfig::Ptr m_shortcutsConfigPtr; friend class LayoutManager; friend class Latte::Corona; }; } #endif //UNIVERSALSETTINGS_H diff --git a/app/view/dockconfigview.cpp b/app/view/dockconfigview.cpp index e4c7bbce..9bcc52db 100644 --- a/app/view/dockconfigview.cpp +++ b/app/view/dockconfigview.cpp @@ -1,585 +1,585 @@ /* * 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 "dockconfigview.h" // local #include "view.h" #include "panelshadows_p.h" #include "../lattecorona.h" #include "../layoutmanager.h" #include "../settings/universalsettings.h" #include "../wm/abstractwindowinterface.h" // Qt #include #include #include #include #include // KDE #include #include #include #include #include // Plasma #include namespace Latte { DockConfigView::DockConfigView(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); connections << connect(&m_screenSyncTimer, &QTimer::timeout, this, [this]() { setScreen(m_latteView->screen()); setFlags(wFlags()); syncGeometry(); syncSlideEffect(); }); connections << connect(m_latteView->visibility(), &VisibilityManager::modeChanged, this, &DockConfigView::syncGeometry); connections << connect(containment, &Plasma::Containment::immutabilityChanged, this, &DockConfigView::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, &DockConfigView::raiseDocksTemporaryChanged); } } DockConfigView::~DockConfigView() { qDebug() << "DockConfigView deleting ..."; deleteSecondaryWindow(); foreach (auto var, connections) { QObject::disconnect(var); } if (m_shellSurface) { delete m_shellSurface; m_shellSurface = nullptr; } } void DockConfigView::init() { qDebug() << "dock config view : initialization started..."; setDefaultAlphaBuffer(true); setColor(Qt::transparent); PanelShadows::self()->addWindow(this); rootContext()->setContextProperty(QStringLiteral("dock"), m_latteView); rootContext()->setContextProperty(QStringLiteral("dockConfig"), 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 DockConfigView::wFlags() const { return (flags() | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint) & ~Qt::WindowDoesNotAcceptFocus; } QWindow *DockConfigView::secondaryWindow() { return m_secConfigView; } void DockConfigView::setAdvanced(bool advanced) { if (m_advanced == advanced) { return; } m_advanced = advanced; if (m_advanced) { createSecondaryWindow(); } else { deleteSecondaryWindow(); } } void DockConfigView::createSecondaryWindow() { //! do not proceed when secondary window is already created //! or when main dock settings window has not updated yet //! its geometry if (m_secConfigView || geometryWhenVisible().isNull()) { return; } QRect geometry = m_latteView->screenGeometry(); m_secConfigView = new DockSecConfigView(m_latteView, this); m_secConfigView->init(); if (m_secConfigView->geometryWhenVisible().intersects(geometryWhenVisible())) { setShowInlineProperties(true); m_secConfigView->hideConfigWindow(); } else { if (!KWindowSystem::isPlatformWayland()) { QTimer::singleShot(150, m_secConfigView, SLOT(show())); } else { QTimer::singleShot(150, [this]() { m_secConfigView->setVisible(true); }); } setShowInlineProperties(false); } } void DockConfigView::deleteSecondaryWindow() { if (m_secConfigView) { m_secConfigView->deleteLater(); } } QRect DockConfigView::geometryWhenVisible() const { return m_geometryWhenVisible; } void DockConfigView::syncGeometry() { if (!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}; switch (m_latteView->containment()->formFactor()) { case Plasma::Types::Horizontal: { if (location == Plasma::Types::TopEdge) { position = {sGeometry.center().x() - size.width() / 2 , sGeometry.y() + clearThickness }; } else if (location == Plasma::Types::BottomEdge) { position = {sGeometry.center().x() - size.width() / 2 , sGeometry.y() + sGeometry.height() - clearThickness - size.height() }; } } break; case Plasma::Types::Vertical: { if (location == Plasma::Types::LeftEdge) { position = {sGeometry.x() + clearThickness , sGeometry.center().y() - size.height() / 2 }; } else if (location == Plasma::Types::RightEdge) { position = {sGeometry.x() + sGeometry.width() - clearThickness - size.width() , sGeometry.center().y() - size.height() / 2 }; } } break; default: qWarning() << "no sync geometry, wrong formFactor"; break; } updateEnabledBorders(); m_geometryWhenVisible = QRect(position.x(), position.y(), size.width(), size.height()); setPosition(position); if (m_shellSurface) { m_shellSurface->setPosition(position); } if (m_advanced) { //! consider even the secondary window can be create createSecondaryWindow(); } } void DockConfigView::syncSlideEffect() { if (!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 DockConfigView::showEvent(QShowEvent *ev) { QQuickWindow::showEvent(ev); 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, &DockConfigView::syncGeometry); emit showSignal(); } void DockConfigView::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(); const auto previousByPassWMBehavior = (m_latteView->flags() & Qt::BypassWindowManagerHint) ? true : false; - if (mode == Dock::AlwaysVisible || mode == Dock::WindowsGoBelow) { + if (mode == Types::AlwaysVisible || mode == Types::WindowsGoBelow) { if (!previousByPassWMBehavior) { m_latteView->managedLayout()->recreateView(m_latteView->containment()); } } else if (m_latteView->byPassWM() != previousByPassWMBehavior) { m_latteView->managedLayout()->recreateView(m_latteView->containment()); } deleteLater(); } void DockConfigView::focusOutEvent(QFocusEvent *ev) { Q_UNUSED(ev); const auto *focusWindow = qGuiApp->focusWindow(); if (focusWindow && (focusWindow->flags().testFlag(Qt::Popup) || focusWindow->flags().testFlag(Qt::ToolTip))) return; if (!m_blockFocusLost && (!m_secConfigView || (m_secConfigView && !m_secConfigView->isActive()))) { hideConfigWindow(); } } void DockConfigView::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 DockConfigView::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 DockConfigView::immutabilityChanged(Plasma::Types::ImmutabilityType type) { if (type != Plasma::Types::Mutable && isVisible()) hideConfigWindow(); } bool DockConfigView::sticker() const { return m_blockFocusLost; } void DockConfigView::setSticker(bool blockFocusLost) { if (m_blockFocusLost == blockFocusLost) return; m_blockFocusLost = blockFocusLost; } bool DockConfigView::showInlineProperties() const { return m_showInlineProperties; } void DockConfigView::setShowInlineProperties(bool show) { if (m_showInlineProperties == show) { return; } m_showInlineProperties = show; emit showInlinePropertiesChanged(); } void DockConfigView::addPanelSpacer() { if (m_latteView && m_latteView->containment()) { m_latteView->containment()->createApplet(QStringLiteral("org.kde.latte.spacer")); } } void DockConfigView::hideConfigWindow() { if (m_shellSurface) { //!NOTE: Avoid crash in wayland environment with qt5.9 close(); } else { hide(); } } void DockConfigView::updateLaunchersForGroup(int groupInt) { - Dock::LaunchersGroup group = (Dock::LaunchersGroup)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 == Dock::LayoutLaunchers && m_latteView->managedLayout()->launchers().isEmpty()) - || (group == Dock::GlobalLaunchers && m_corona->universalSettings()->launchers().isEmpty())) { + 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 == Dock::LayoutLaunchers) { + if (group == Types::LayoutLaunchers) { m_latteView->managedLayout()->setLaunchers(launchers.toStringList()); - } else if (group == Dock::GlobalLaunchers) { + } else if (group == Types::GlobalLaunchers) { m_corona->universalSettings()->setLaunchers(launchers.toStringList()); } } } } } } } } } } //!BEGIN borders Plasma::FrameSvg::EnabledBorders DockConfigView::enabledBorders() const { return m_enabledBorders; } void DockConfigView::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 } // kate: indent-mode cstyle; indent-width 4; replace-tabs on; diff --git a/app/view/dockconfigview.h b/app/view/dockconfigview.h index e2cecd1f..9b67a48b 100644 --- a/app/view/dockconfigview.h +++ b/app/view/dockconfigview.h @@ -1,145 +1,145 @@ /* * 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 . */ #ifndef DOCKCONFIGVIEW_H #define DOCKCONFIGVIEW_H // local #include "docksecconfigview.h" #include "../plasmaquick/configview.h" -#include "../../liblattedock/dock.h" +#include "../../liblatte2/types.h" //Qt #include #include #include #include // Plasma #include #include namespace Plasma { class Applet; class Containment; class FrameSvg; class Types; } namespace KWayland { namespace Client { class PlasmaShellSurface; } } namespace Latte { class Corona; class View; } namespace Latte { class DockConfigView : public PlasmaQuick::ConfigView { Q_OBJECT //! used when the secondary config window can not be shown Q_PROPERTY(bool showInlineProperties READ showInlineProperties WRITE setShowInlineProperties NOTIFY showInlinePropertiesChanged) Q_PROPERTY(Plasma::FrameSvg::EnabledBorders enabledBorders READ enabledBorders NOTIFY enabledBordersChanged) public: enum ConfigViewType { PrimaryConfig = 0, SecondaryConfig }; DockConfigView(Plasma::Containment *containment, Latte::View *view, QWindow *parent = nullptr); ~DockConfigView() override; void init() override; Qt::WindowFlags wFlags() const; bool showInlineProperties() const; void setShowInlineProperties(bool show); bool sticker() const; QRect geometryWhenVisible() const; Plasma::FrameSvg::EnabledBorders enabledBorders() const; QWindow *secondaryWindow(); public slots: Q_INVOKABLE void addPanelSpacer(); Q_INVOKABLE void hideConfigWindow(); Q_INVOKABLE void setSticker(bool blockFocusLost); Q_INVOKABLE void syncGeometry(); Q_INVOKABLE void updateLaunchersForGroup(int groupInt); Q_INVOKABLE void setAdvanced(bool advanced); signals: void enabledBordersChanged(); void raiseDocksTemporaryChanged(); void showInlinePropertiesChanged(); void showSignal(); protected: void showEvent(QShowEvent *ev) override; void hideEvent(QHideEvent *ev) override; void focusOutEvent(QFocusEvent *ev) override; bool event(QEvent *e) override; void syncSlideEffect(); private slots: void immutabilityChanged(Plasma::Types::ImmutabilityType type); void updateEnabledBorders(); void createSecondaryWindow(); void deleteSecondaryWindow(); private: void setupWaylandIntegration(); bool m_advanced{false}; bool m_blockFocusLost{false}; bool m_blockFocusLostOnStartup{true}; bool m_inReverse{false}; //! it is used by the borders bool m_showInlineProperties{false}; QRect m_geometryWhenVisible; QPointer m_latteView; QPointer m_secConfigView; QTimer m_screenSyncTimer; QTimer m_thicknessSyncTimer; QList connections; Plasma::FrameSvg::EnabledBorders m_enabledBorders{Plasma::FrameSvg::AllBorders}; Latte::Corona *m_corona{nullptr}; KWayland::Client::PlasmaShellSurface *m_shellSurface{nullptr}; }; } #endif //DOCKCONFIGVIEW_H // kate: indent-mode cstyle; indent-width 4; replace-tabs on; diff --git a/app/view/docksecconfigview.h b/app/view/docksecconfigview.h index ed2a43aa..2bafd0ba 100644 --- a/app/view/docksecconfigview.h +++ b/app/view/docksecconfigview.h @@ -1,110 +1,110 @@ /* * Copyright 2018 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 DOCKSECCONFIGVIEW_H #define DOCKSECCONFIGVIEW_H // local -#include "../../liblattedock/dock.h" +#include "../../liblatte2/types.h" //Qt #include #include #include #include // Plasma #include #include namespace Plasma { class Applet; class Containment; class FrameSvg; class Types; } namespace KWayland { namespace Client { class PlasmaShellSurface; } } namespace Latte { class Corona; class View; } namespace Latte { class DockSecConfigView : public QQuickView { Q_OBJECT Q_PROPERTY(Plasma::FrameSvg::EnabledBorders enabledBorders READ enabledBorders NOTIFY enabledBordersChanged) public: DockSecConfigView(Latte::View *view, QWindow *parent); ~DockSecConfigView() override; void init(); Qt::WindowFlags wFlags() const; QRect geometryWhenVisible() const; Plasma::FrameSvg::EnabledBorders enabledBorders() const; public slots: Q_INVOKABLE void hideConfigWindow(); Q_INVOKABLE void syncGeometry(); signals: void enabledBordersChanged(); void showSignal(); protected: void showEvent(QShowEvent *ev) override; void focusOutEvent(QFocusEvent *ev) override; bool event(QEvent *e) override; void syncSlideEffect(); private slots: void updateEnabledBorders(); private: void setupWaylandIntegration(); QRect m_geometryWhenVisible; QPointer m_latteView; QPointer m_parent; QTimer m_screenSyncTimer; QTimer m_thicknessSyncTimer; QList connections; Plasma::FrameSvg::EnabledBorders m_enabledBorders{Plasma::FrameSvg::AllBorders}; Latte::Corona *m_corona{nullptr}; KWayland::Client::PlasmaShellSurface *m_shellSurface{nullptr}; }; } #endif //DOCKSECCONFIGVIEW_H // kate: indent-mode cstyle; indent-width 4; replace-tabs on; diff --git a/app/view/effects.cpp b/app/view/effects.cpp index 07c09b32..740d6cfb 100644 --- a/app/view/effects.cpp +++ b/app/view/effects.cpp @@ -1,400 +1,400 @@ /* * Copyright 2018 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 "effects.h" // local #include "panelshadows_p.h" #include "view.h" -#include "../../liblattedock/dock.h" +#include "../../liblatte2/types.h" // Qt #include // KDE #include #include namespace Latte { namespace ViewPart { Effects::Effects(Latte::View *parent) : QObject(parent), m_view(parent) { init(); } Effects::~Effects() { } void Effects::init() { connect(this, &Effects::backgroundOpacityChanged, this, &Effects::updateEffects); connect(this, &Effects::drawEffectsChanged, this, &Effects::updateEffects); connect(this, &Effects::rectChanged, this, &Effects::updateEffects); connect(this, &Effects::drawShadowsChanged, this, [&]() { if (m_view->behaveAsPlasmaPanel()) { updateEnabledBorders(); } }); connect(m_view, &Latte::View::alignmentChanged, this, &Effects::updateEnabledBorders); connect(m_view, &Latte::View::behaveAsPlasmaPanelChanged, this, &Effects::updateEffects); connect(m_view, &Latte::View::behaveAsPlasmaPanelChanged, this, &Effects::updateShadows); connect(this, SIGNAL(innerShadowChanged()), m_view->corona(), SIGNAL(availableScreenRectChanged())); } bool Effects::animationsBlocked() const { return m_animationsBlocked; } void Effects::setAnimationsBlocked(bool blocked) { if (m_animationsBlocked == blocked) { return; } m_animationsBlocked = blocked; emit animationsBlockedChanged(); } bool Effects::colorizerEnabled() const { return m_colorizerEnabled; } void Effects::setColorizerEnabled(bool enabled) { if (m_colorizerEnabled == enabled) { return; } m_colorizerEnabled = enabled; emit colorizerEnabledChanged(); } bool Effects::drawShadows() const { return m_drawShadows; } void Effects::setDrawShadows(bool draw) { if (m_drawShadows == draw) { return; } m_drawShadows = draw; if (m_view->behaveAsPlasmaPanel() && m_drawShadows) { PanelShadows::self()->addWindow(m_view, m_enabledBorders); } else { PanelShadows::self()->removeWindow(m_view); } emit drawShadowsChanged(); } bool Effects::drawEffects() const { return m_drawEffects; } void Effects::setDrawEffects(bool draw) { if (m_drawEffects == draw) { return; } m_drawEffects = draw; emit drawEffectsChanged(); } bool Effects::forceDrawCenteredBorders() const { return m_forceDrawCenteredBorders; } void Effects::setForceDrawCenteredBorders(bool draw) { if (m_forceDrawCenteredBorders == draw) { return; } m_forceDrawCenteredBorders = draw; } int Effects::backgroundOpacity() const { return m_backgroundOpacity; } void Effects::setBackgroundOpacity(int opacity) { if (m_backgroundOpacity == opacity) { return; } m_backgroundOpacity = opacity; emit backgroundOpacityChanged(); } int Effects::innerShadow() const { return m_innerShadow; } void Effects::setInnerShadow(int shadow) { if (m_innerShadow == shadow) return; m_innerShadow = shadow; emit innerShadowChanged(); } QRect Effects::rect() const { return m_rect; } void Effects::setRect(QRect area) { QRect inWindowRect = area.intersected(QRect(0, 0, m_view->width(), m_view->height())); if (m_rect == inWindowRect) { return; } m_rect = inWindowRect; emit rectChanged(); } QRect Effects::mask() const { return m_mask; } void Effects::setMask(QRect area) { if (m_mask == area) return; m_mask = area; if (KWindowSystem::compositingActive()) { if (m_view->behaveAsPlasmaPanel()) { m_view->setMask(QRect()); } else { m_view->setMask(m_mask); } } else { //! this is used when compositing is disabled and provides //! the correct way for the mask to be painted in order for //! rounded corners to be shown correctly //! the enabledBorders check was added because there was cases //! that the mask region wasnt calculated correctly after location changes if (!m_background || m_background->enabledBorders() != m_enabledBorders) { m_background = new Plasma::FrameSvg(this); } if (m_background->imagePath() != "opaque/dialogs/background") { m_background->setImagePath(QStringLiteral("opaque/dialogs/background")); } m_background->setEnabledBorders(m_enabledBorders); m_background->resizeFrame(area.size()); QRegion fixedMask = m_background->mask(); fixedMask.translate(m_mask.x(), m_mask.y()); //! fix for KF5.32 that return empty QRegion's for the mask if (fixedMask.isEmpty()) { fixedMask = QRegion(m_mask); } m_view->setMask(fixedMask); } // qDebug() << "dock mask set:" << m_mask; emit maskChanged(); } void Effects::clearShadows() { PanelShadows::self()->removeWindow(m_view); } void Effects::updateShadows() { if (m_view->behaveAsPlasmaPanel() && drawShadows()) { PanelShadows::self()->addWindow(m_view, enabledBorders()); } else { PanelShadows::self()->removeWindow(m_view); } } void Effects::updateEffects() { //! Don't apply any effect before the wayland surface is created under wayland //! https://bugs.kde.org/show_bug.cgi?id=392890 if (KWindowSystem::isPlatformWayland() && !m_view->surface()) { return; } if (!m_view->behaveAsPlasmaPanel()) { if (m_drawEffects && !m_rect.isNull() && !m_rect.isEmpty()) { //! this is used when compositing is disabled and provides //! the correct way for the mask to be painted in order for //! rounded corners to be shown correctly if (!m_background) { m_background = new Plasma::FrameSvg(this); } if (m_background->imagePath() != "widgets/panel-background") { m_background->setImagePath(QStringLiteral("widgets/panel-background")); } m_background->setEnabledBorders(m_enabledBorders); m_background->resizeFrame(m_rect.size()); QRegion fixedMask = m_background->mask(); fixedMask.translate(m_rect.x(), m_rect.y()); //! fix1, for KF5.32 that return empty QRegion's for the mask if (fixedMask.isEmpty()) { fixedMask = QRegion(m_rect); } KWindowEffects::enableBlurBehind(m_view->winId(), true, fixedMask); bool drawBackgroundEffect = m_theme.backgroundContrastEnabled() && (m_backgroundOpacity == 100); //based on Breeze Dark theme behavior the enableBackgroundContrast even though it does accept //a QRegion it uses only the first rect. The bug was that for Breeze Dark there was a line //at the dock bottom that was distinguishing it from other themes KWindowEffects::enableBackgroundContrast(m_view->winId(), drawBackgroundEffect, m_theme.backgroundContrast(), m_theme.backgroundIntensity(), m_theme.backgroundSaturation(), fixedMask.boundingRect()); } else { KWindowEffects::enableBlurBehind(m_view->winId(), false); KWindowEffects::enableBackgroundContrast(m_view->winId(), false); } } else if (m_view->behaveAsPlasmaPanel() && m_drawEffects) { KWindowEffects::enableBlurBehind(m_view->winId(), true); bool drawBackgroundEffect = m_theme.backgroundContrastEnabled() && (m_backgroundOpacity == 100); KWindowEffects::enableBackgroundContrast(m_view->winId(), drawBackgroundEffect, m_theme.backgroundContrast(), m_theme.backgroundIntensity(), m_theme.backgroundSaturation()); } else { KWindowEffects::enableBlurBehind(m_view->winId(), false); KWindowEffects::enableBackgroundContrast(m_view->winId(), false); } } //!BEGIN draw panel shadows outside the dock window Plasma::FrameSvg::EnabledBorders Effects::enabledBorders() const { return m_enabledBorders; } void Effects::updateEnabledBorders() { if (!m_view->screen()) { return; } Plasma::FrameSvg::EnabledBorders borders = Plasma::FrameSvg::AllBorders; switch (m_view->location()) { case Plasma::Types::TopEdge: borders &= ~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 &= ~Plasma::FrameSvg::BottomBorder; break; default: break; } if ((m_view->location() == Plasma::Types::LeftEdge || m_view->location() == Plasma::Types::RightEdge)) { - if (m_view->maxLength() == 1 && m_view->alignment() == Latte::Dock::Justify && !m_forceDrawCenteredBorders) { + if (m_view->maxLength() == 1 && m_view->alignment() == Latte::Types::Justify && !m_forceDrawCenteredBorders) { borders &= ~Plasma::FrameSvg::TopBorder; borders &= ~Plasma::FrameSvg::BottomBorder; } - if (m_view->alignment() == Latte::Dock::Top && !m_forceDrawCenteredBorders && m_view->offset() == 0) { + if (m_view->alignment() == Latte::Types::Top && !m_forceDrawCenteredBorders && m_view->offset() == 0) { borders &= ~Plasma::FrameSvg::TopBorder; } - if (m_view->alignment() == Latte::Dock::Bottom && !m_forceDrawCenteredBorders && m_view->offset() == 0) { + if (m_view->alignment() == Latte::Types::Bottom && !m_forceDrawCenteredBorders && m_view->offset() == 0) { borders &= ~Plasma::FrameSvg::BottomBorder; } } if (m_view->location() == Plasma::Types::TopEdge || m_view->location() == Plasma::Types::BottomEdge) { - if (m_view->maxLength() == 1 && m_view->alignment() == Latte::Dock::Justify) { + if (m_view->maxLength() == 1 && m_view->alignment() == Latte::Types::Justify) { borders &= ~Plasma::FrameSvg::LeftBorder; borders &= ~Plasma::FrameSvg::RightBorder; } - if (m_view->alignment() == Latte::Dock::Left && m_view->offset() == 0) { + if (m_view->alignment() == Latte::Types::Left && m_view->offset() == 0) { borders &= ~Plasma::FrameSvg::LeftBorder; } - if (m_view->alignment() == Latte::Dock::Right && m_view->offset() == 0) { + if (m_view->alignment() == Latte::Types::Right && m_view->offset() == 0) { borders &= ~Plasma::FrameSvg::RightBorder; } } if (m_enabledBorders != borders) { m_enabledBorders = borders; emit enabledBordersChanged(); } if (!m_view->behaveAsPlasmaPanel() || !m_drawShadows) { PanelShadows::self()->removeWindow(m_view); } else { PanelShadows::self()->setEnabledBorders(m_view, borders); } } //!END draw panel shadows outside the dock window } } diff --git a/app/view/positioner.cpp b/app/view/positioner.cpp index d3e5c378..76b23af1 100644 --- a/app/view/positioner.cpp +++ b/app/view/positioner.cpp @@ -1,664 +1,664 @@ /* * Copyright 2018 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 "positioner.h" // local #include "effects.h" #include "view.h" #include "../lattecorona.h" #include "../screenpool.h" #include "../settings/universalsettings.h" -#include "../../liblattedock/dock.h" +#include "../../liblatte2/types.h" // Qt #include // KDE #include #include #include namespace Latte { namespace ViewPart { Positioner::Positioner(Latte::View *parent) : QObject(parent), m_view(parent) { m_screenSyncTimer.setSingleShot(true); m_screenSyncTimer.setInterval(2000); connect(&m_screenSyncTimer, &QTimer::timeout, this, &Positioner::reconsiderScreen); //! under X11 it was identified that windows many times especially under screen changes //! don't end up at the correct position and size. This timer will enforce repositionings //! and resizes every 500ms if the window hasn't end up to correct values and until this //! is achieved m_validateGeometryTimer.setSingleShot(true); m_validateGeometryTimer.setInterval(500); connect(&m_validateGeometryTimer, &QTimer::timeout, this, &Positioner::syncGeometry); auto *latteCorona = qobject_cast(m_view->corona()); if (latteCorona) { m_screenSyncTimer.setInterval(qMax(latteCorona->universalSettings()->screenTrackerInterval() - 500, 1000)); connect(latteCorona->universalSettings(), &UniversalSettings::screenTrackerIntervalChanged, this, [this, latteCorona]() { m_screenSyncTimer.setInterval(qMax(latteCorona->universalSettings()->screenTrackerInterval() - 500, 1000)); }); connect(latteCorona, &Latte::Corona::viewLocationChanged, this, [&]() { //! check if an edge has been freed for a primary dock //! from another screen if (m_view->onPrimary()) { m_screenSyncTimer.start(); } }); } init(); } Positioner::~Positioner() { m_inDelete = true; m_screenSyncTimer.stop(); m_validateGeometryTimer.stop(); } void Positioner::init() { //! connections connect(this, &Positioner::screenGeometryChanged, this, &Positioner::syncGeometry); connect(m_view, &QQuickWindow::xChanged, this, &Positioner::validateDockGeometry); connect(m_view, &QQuickWindow::yChanged, this, &Positioner::validateDockGeometry); connect(m_view, &QQuickWindow::widthChanged, this, &Positioner::validateDockGeometry); connect(m_view, &QQuickWindow::heightChanged, this, &Positioner::validateDockGeometry); connect(m_view, &QQuickWindow::screenChanged, this, &Positioner::currentScreenChanged); connect(m_view, &QQuickWindow::screenChanged, this, &Positioner::screenChanged); connect(m_view, &Latte::View::absGeometryChanged, this, &Positioner::syncGeometry); connect(m_view, &Latte::View::behaveAsPlasmaPanelChanged, this, &Positioner::syncGeometry); connect(m_view, &Latte::View::maxThicknessChanged, this, &Positioner::syncGeometry); connect(m_view, &Latte::View::maxLengthChanged, this, &Positioner::syncGeometry); connect(m_view, &Latte::View::offsetChanged, this, &Positioner::syncGeometry); connect(m_view, &Latte::View::locationChanged, this, [&]() { updateFormFactor(); syncGeometry(); }); connect(m_view, &Latte::View::normalThicknessChanged, this, [&]() { if (m_view->behaveAsPlasmaPanel()) { syncGeometry(); } }); connect(m_view->effects(), &Latte::ViewPart::Effects::drawShadowsChanged, this, [&]() { if (!m_view->behaveAsPlasmaPanel()) { syncGeometry(); } }); connect(m_view->effects(), &Latte::ViewPart::Effects::innerShadowChanged, this, [&]() { if (m_view->behaveAsPlasmaPanel()) { syncGeometry(); } }); connect(qGuiApp, &QGuiApplication::screenAdded, this, &Positioner::screenChanged); connect(qGuiApp, &QGuiApplication::primaryScreenChanged, this, &Positioner::screenChanged); initSignalingForLocationChangeSliding(); } int Positioner::currentScreenId() const { auto *latteCorona = qobject_cast(m_view->corona()); if (latteCorona) { return latteCorona->screenPool()->id(m_screenToFollowId); } return -1; } QString Positioner::currentScreenName() const { return m_screenToFollowId; } bool Positioner::setCurrentScreen(const QString id) { QScreen *nextScreen{qGuiApp->primaryScreen()}; if (id != "primary") { foreach (auto scr, qGuiApp->screens()) { if (scr && scr->name() == id) { nextScreen = scr; break; } } } if (m_screenToFollow == nextScreen) { return true; } if (nextScreen) { if (m_view->managedLayout()) { auto freeEdges = m_view->managedLayout()->freeEdges(nextScreen); if (!freeEdges.contains(m_view->location())) { return false; } else { m_goToScreen = nextScreen; //! asynchronous call in order to not crash from configwindow //! deletion from sliding out animation QTimer::singleShot(100, [this]() { emit hideDockDuringScreenChangeStarted(); }); } } } return true; } //! this function updates the dock's associated screen. //! updateScreenId = true, update also the m_screenToFollowId //! updateScreenId = false, do not update the m_screenToFollowId //! that way an explicit dock can be shown in another screen when //! there isnt a tasks dock running in the system and for that //! dock its first origin screen is stored and that way when //! that screen is reconnected the dock will return to its original //! place void Positioner::setScreenToFollow(QScreen *scr, bool updateScreenId) { if (!scr || (scr && (m_screenToFollow == scr) && (m_view->screen() == scr))) { return; } qDebug() << "setScreenToFollow() called for screen:" << scr->name() << " update:" << updateScreenId; m_screenToFollow = scr; if (updateScreenId) { m_screenToFollowId = scr->name(); } qDebug() << "adapting to screen..."; m_view->setScreen(scr); if (m_view->containment()) { m_view->containment()->reactToScreenChange(); } connect(scr, &QScreen::geometryChanged, this, &Positioner::screenGeometryChanged); syncGeometry(); m_view->updateAbsDockGeometry(true); qDebug() << "setScreenToFollow() ended..."; emit screenGeometryChanged(); emit currentScreenChanged(); } //! the main function which decides if this dock is at the //! correct screen void Positioner::reconsiderScreen() { if (m_inDelete) { return; } qDebug() << "reconsiderScreen() called..."; qDebug() << " Delayer "; foreach (auto scr, qGuiApp->screens()) { qDebug() << " D, found screen: " << scr->name(); } bool screenExists{false}; //!check if the associated screen is running foreach (auto scr, qGuiApp->screens()) { if (m_screenToFollowId == scr->name() || (m_view->onPrimary() && scr == qGuiApp->primaryScreen())) { screenExists = true; } } qDebug() << "dock screen exists ::: " << screenExists; //! 1.a primary dock must be always on the primary screen if (m_view->onPrimary() && (m_screenToFollowId != qGuiApp->primaryScreen()->name() || m_screenToFollow != qGuiApp->primaryScreen() || m_view->screen() != qGuiApp->primaryScreen())) { using Plasma::Types; QList edges{Types::BottomEdge, Types::LeftEdge, Types::TopEdge, Types::RightEdge}; edges = m_view->managedLayout() ? m_view->managedLayout()->availableEdgesForView(qGuiApp->primaryScreen(), m_view) : edges; //change to primary screen only if the specific edge is free qDebug() << "updating the primary screen for dock..."; qDebug() << "available primary screen edges:" << edges; qDebug() << "dock location:" << m_view->location(); if (edges.contains(m_view->location())) { //! case 1 qDebug() << "reached case 1: of updating dock primary screen..."; setScreenToFollow(qGuiApp->primaryScreen()); } } else if (!m_view->onPrimary()) { //! 2.an explicit dock must be always on the correct associated screen //! there are cases that window manager misplaces the dock, this function //! ensures that this dock will return at its correct screen foreach (auto scr, qGuiApp->screens()) { if (scr && scr->name() == m_screenToFollowId) { qDebug() << "reached case 2: updating the explicit screen for dock..."; setScreenToFollow(scr); break; } } } syncGeometry(); qDebug() << "reconsiderScreen() ended..."; } void Positioner::screenChanged(QScreen *scr) { m_screenSyncTimer.start(); //! this is needed in order to update the struts on screen change //! and even though the geometry has been set correctly the offsets //! of the screen must be updated to the new ones - if (m_view->visibility() && m_view->visibility()->mode() == Latte::Dock::AlwaysVisible) { + if (m_view->visibility() && m_view->visibility()->mode() == Latte::Types::AlwaysVisible) { m_view->updateAbsDockGeometry(true); } } void Positioner::syncGeometry() { if (!(m_view->screen() && m_view->containment()) || m_inDelete) { return; } bool found{false}; qDebug() << "syncGeometry() called..."; //! before updating the positioning and geometry of the dock //! we make sure that the dock is at the correct screen if (m_view->screen() != m_screenToFollow) { qDebug() << "Sync Geometry screens inconsistent!!!! "; if (m_screenToFollow) { qDebug() << "Sync Geometry screens inconsistent for m_screenToFollow:" << m_screenToFollow->name() << " dock screen:" << m_view->screen()->name(); } if (!m_screenSyncTimer.isActive()) { m_screenSyncTimer.start(); } } else { found = true; } //! if the dock isnt at the correct screen the calculations //! are not executed if (found) { //! compute the free screen rectangle for vertical panels only once //! this way the costly QRegion computations are calculated only once //! instead of two times (both inside the resizeWindow and the updatePosition) QRegion freeRegion;; QRect maximumRect; QRect availableScreenRect{m_view->screen()->geometry()}; if (m_view->formFactor() == Plasma::Types::Vertical) { QString layoutName = m_view->managedLayout() ? m_view->managedLayout()->name() : QString(); auto latteCorona = qobject_cast(m_view->corona()); int fixedScreen = m_view->onPrimary() ? latteCorona->screenPool()->primaryScreenId() : m_view->containment()->screen(); freeRegion = latteCorona->availableScreenRegionWithCriteria(fixedScreen, layoutName); maximumRect = maximumNormalGeometry(); QRegion availableRegion = freeRegion.intersected(maximumRect); availableScreenRect = freeRegion.intersected(maximumRect).boundingRect(); float area = 0; //! it is used to choose which or the availableRegion rectangles will //! be the one representing dock geometry for (int i = 0; i < availableRegion.rectCount(); ++i) { QRect rect = availableRegion.rects().at(i); //! the area of each rectangle in calculated in squares of 50x50 //! this is a way to avoid enourmous numbers for area value float tempArea = (float)(rect.width() * rect.height()) / 2500; if (tempArea > area) { availableScreenRect = rect; area = tempArea; } } if (availableRegion.rectCount() > 1 && m_view->behaveAsPlasmaPanel()) { m_view->effects()->setForceDrawCenteredBorders(true); } else { m_view->effects()->setForceDrawCenteredBorders(false); } } else { m_view->effects()->setForceDrawCenteredBorders(false); } m_view->effects()->updateEnabledBorders(); resizeWindow(availableScreenRect); updatePosition(availableScreenRect); qDebug() << "syncGeometry() calculations for screen: " << m_view->screen()->name() << " _ " << m_view->screen()->geometry(); } qDebug() << "syncGeometry() ended..."; // qDebug() << "dock geometry:" << qRectToStr(geometry()); } void Positioner::validateDockGeometry() { if (m_view->geometry() != m_validGeometry) { m_validateGeometryTimer.start(); } } //! this is used mainly from vertical panels in order to //! to get the maximum geometry that can be used from the dock //! based on their alignment type and the location dock QRect Positioner::maximumNormalGeometry() { int xPos = 0; int yPos = 0; int maxHeight = m_view->maxLength() * m_view->screen()->geometry().height(); int maxWidth = m_view->normalThickness(); QRect maxGeometry; maxGeometry.setRect(0, 0, maxWidth, maxHeight); switch (m_view->location()) { case Plasma::Types::LeftEdge: xPos = m_view->screen()->geometry().x(); switch (m_view->alignment()) { - case Latte::Dock::Top: + case Latte::Types::Top: yPos = m_view->screen()->geometry().y(); break; - case Latte::Dock::Center: - case Latte::Dock::Justify: + case Latte::Types::Center: + case Latte::Types::Justify: yPos = qMax(m_view->screen()->geometry().center().y() - maxHeight / 2, m_view->screen()->geometry().y()); break; - case Latte::Dock::Bottom: + case Latte::Types::Bottom: yPos = m_view->screen()->geometry().bottom() - maxHeight + 1; break; } maxGeometry.setRect(xPos, yPos, maxWidth, maxHeight); break; case Plasma::Types::RightEdge: xPos = m_view->screen()->geometry().right() - maxWidth + 1; switch (m_view->alignment()) { - case Latte::Dock::Top: + case Latte::Types::Top: yPos = m_view->screen()->geometry().y(); break; - case Latte::Dock::Center: - case Latte::Dock::Justify: + case Latte::Types::Center: + case Latte::Types::Justify: yPos = qMax(m_view->screen()->geometry().center().y() - maxHeight / 2, m_view->screen()->geometry().y()); break; - case Latte::Dock::Bottom: + case Latte::Types::Bottom: yPos = m_view->screen()->geometry().bottom() - maxHeight + 1; break; } maxGeometry.setRect(xPos, yPos, maxWidth, maxHeight); break; default: //! bypass clang warnings break; } //! this is needed in order to preserve that the top dock will be above //! the others in case flag bypasswindowmanagerhint hasn't be set, //! such a case is the AlwaysVisible mode if (m_view->location() == Plasma::Types::TopEdge) { KWindowSystem::setState(m_view->winId(), NET::KeepAbove); } else { KWindowSystem::clearState(m_view->winId(), NET::KeepAbove); } return maxGeometry; } void Positioner::updatePosition(QRect availableScreenRect) { QRect screenGeometry{availableScreenRect}; QPoint position; position = {0, 0}; const auto length = [&](int length) -> int { float offs = static_cast(m_view->offset()); return static_cast(length * ((1 - m_view->maxLength()) / 2) + length * (offs / 100)); }; int cleanThickness = m_view->normalThickness() - m_view->effects()->innerShadow(); switch (m_view->location()) { case Plasma::Types::TopEdge: if (m_view->behaveAsPlasmaPanel()) { position = {screenGeometry.x() + length(screenGeometry.width()), screenGeometry.y()}; } else { position = {screenGeometry.x(), screenGeometry.y()}; } break; case Plasma::Types::BottomEdge: if (m_view->behaveAsPlasmaPanel()) { position = {screenGeometry.x() + length(screenGeometry.width()), screenGeometry.y() + screenGeometry.height() - cleanThickness }; } else { position = {screenGeometry.x(), screenGeometry.y() + screenGeometry.height() - m_view->height()}; } break; case Plasma::Types::RightEdge: if (m_view->behaveAsPlasmaPanel() && !m_view->mask().isNull()) { position = {availableScreenRect.right() - cleanThickness + 1, availableScreenRect.y() + length(availableScreenRect.height()) }; } else { position = {availableScreenRect.right() - m_view->width() + 1, availableScreenRect.y()}; } break; case Plasma::Types::LeftEdge: if (m_view->behaveAsPlasmaPanel() && !m_view->mask().isNull()) { position = {availableScreenRect.x(), availableScreenRect.y() + length(availableScreenRect.height())}; } else { position = {availableScreenRect.x(), availableScreenRect.y()}; } break; default: qWarning() << "wrong location, couldn't update the panel position" << m_view->location(); } m_validGeometry.setTopLeft(position); m_view->setPosition(position); if (m_view->surface()) { m_view->surface()->setPosition(position); } } void Positioner::resizeWindow(QRect availableScreenRect) { QSize screenSize = m_view->screen()->size(); QSize size = (m_view->formFactor() == Plasma::Types::Vertical) ? QSize(m_view->maxThickness(), availableScreenRect.height()) : QSize(screenSize.width(), m_view->maxThickness()); if (m_view->formFactor() == Plasma::Types::Vertical) { //qDebug() << "MAXIMUM RECT :: " << maximumRect << " - AVAILABLE RECT :: " << availableRect; if (m_view->behaveAsPlasmaPanel()) { size.setWidth(m_view->normalThickness()); size.setHeight(static_cast(m_view->maxLength() * availableScreenRect.height())); } } else { if (m_view->behaveAsPlasmaPanel()) { size.setWidth(static_cast(m_view->maxLength() * screenSize.width())); size.setHeight(m_view->normalThickness()); } } m_validGeometry.setSize(size); m_view->setMinimumSize(size); m_view->setMaximumSize(size); m_view->resize(size); if (m_view->formFactor() == Plasma::Types::Horizontal && m_view->corona()) { emit m_view->corona()->availableScreenRectChanged(); } } void Positioner::updateFormFactor() { if (!m_view->containment()) return; switch (m_view->location()) { case Plasma::Types::TopEdge: case Plasma::Types::BottomEdge: m_view->containment()->setFormFactor(Plasma::Types::Horizontal); break; case Plasma::Types::LeftEdge: case Plasma::Types::RightEdge: m_view->containment()->setFormFactor(Plasma::Types::Vertical); break; default: qWarning() << "wrong location, couldn't update the panel position" << m_view->location(); } } void Positioner::initSignalingForLocationChangeSliding() { //! signals to handle the sliding-in/out during location changes connect(this, &Positioner::hideDockDuringLocationChangeStarted, this, &Positioner::onHideWindowsForSlidingOut); connect(m_view, &View::locationChanged, this, [&]() { if (m_goToLocation != Plasma::Types::Floating) { m_goToLocation = Plasma::Types::Floating; QTimer::singleShot(100, [this]() { m_view->effects()->setAnimationsBlocked(false); emit showDockAfterLocationChangeFinished(); m_view->showSettingsWindow(); if (m_view->managedLayout()) { m_view->managedLayout()->syncLatteViewsToScreens(); } }); } }); //! signals to handle the sliding-in/out during screen changes connect(this, &Positioner::hideDockDuringScreenChangeStarted, this, &Positioner::onHideWindowsForSlidingOut); connect(this, &Positioner::currentScreenChanged, this, [&]() { if (m_goToScreen) { m_goToScreen = nullptr; QTimer::singleShot(100, [this]() { m_view->effects()->setAnimationsBlocked(false); emit showDockAfterScreenChangeFinished(); m_view->showSettingsWindow(); if (m_view->managedLayout()) { m_view->managedLayout()->syncLatteViewsToScreens(); } }); } }); //! signals to handle the sliding-in/out during moving to another layout connect(this, &Positioner::hideDockDuringMovingToLayoutStarted, this, &Positioner::onHideWindowsForSlidingOut); connect(m_view, &View::managedLayoutChanged, this, [&]() { if (!m_moveToLayout.isEmpty() && m_view->managedLayout()) { m_moveToLayout = ""; QTimer::singleShot(100, [this]() { m_view->effects()->setAnimationsBlocked(false); emit showDockAfterMovingToLayoutFinished(); m_view->showSettingsWindow(); }); } }); //! ---- both cases ---- !// //! this is used for both location and screen change cases, this signal //! is send when the sliding-out animation has finished connect(this, &Positioner::hideDockDuringLocationChangeFinished, this, [&]() { m_view->effects()->setAnimationsBlocked(true); if (m_goToLocation != Plasma::Types::Floating) { m_view->setLocation(m_goToLocation); } else if (m_goToScreen) { setScreenToFollow(m_goToScreen); } else if (!m_moveToLayout.isEmpty()) { m_view->moveToLayout(m_moveToLayout); } }); } bool Positioner::inLocationChangeAnimation() { return ((m_goToLocation != Plasma::Types::Floating) || (m_moveToLayout != "") || m_goToScreen); } void Positioner::hideDockDuringLocationChange(int goToLocation) { m_goToLocation = static_cast(goToLocation); emit hideDockDuringLocationChangeStarted(); } void Positioner::hideDockDuringMovingToLayout(QString layoutName) { m_moveToLayout = layoutName; emit hideDockDuringMovingToLayoutStarted(); } } } diff --git a/app/view/view.cpp b/app/view/view.cpp index eb84e59d..7f48e2f6 100644 --- a/app/view/view.cpp +++ b/app/view/view.cpp @@ -1,1071 +1,1071 @@ /* * 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 "view.h" // local #include "contextmenu.h" #include "dockconfigview.h" #include "effects.h" #include "positioner.h" #include "visibilitymanager.h" #include "../lattecorona.h" #include "../layout.h" #include "../layoutmanager.h" #include "../screenpool.h" #include "../plasmathemeextended.h" #include "../settings/universalsettings.h" -#include "../../liblattedock/extras.h" +#include "../../liblatte2/extras.h" // Qt #include #include #include #include #include #include // KDe #include #include #include #include #include // Plasma #include #include #include namespace Latte { //! both alwaysVisible and byPassWM are passed through corona because //! during the view window creation containment hasn't been set, but these variables //! are needed in order for window flags to be set correctly View::View(Plasma::Corona *corona, QScreen *targetScreen, bool byPassWM) : PlasmaQuick::ContainmentView(corona), m_contextMenu(new ViewPart::ContextMenu(this)), m_effects(new ViewPart::Effects(this)), m_positioner(new ViewPart::Positioner(this)) //needs to be created after Effects becuase it catches some of its signals { setTitle(corona->kPackage().metadata().name()); setIcon(qGuiApp->windowIcon()); setResizeMode(QuickViewSharedEngine::SizeRootObjectToView); setColor(QColor(Qt::transparent)); setClearBeforeRendering(true); const auto flags = Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::NoDropShadowWindowHint | Qt::WindowDoesNotAcceptFocus; if (byPassWM) { setFlags(flags | Qt::BypassWindowManagerHint); } else { setFlags(flags); } KWindowSystem::setOnAllDesktops(winId(), true); if (targetScreen) m_positioner->setScreenToFollow(targetScreen); else m_positioner->setScreenToFollow(qGuiApp->primaryScreen()); connect(this, &View::containmentChanged , this, [ &, byPassWM]() { qDebug() << "dock view c++ containment changed 1..."; if (!this->containment()) return; qDebug() << "dock view c++ containment changed 2..."; //! First load default values from file restoreConfig(); //! Afterwards override that values in case during creation something different is needed setByPassWM(byPassWM); //! Check the screen assigned to this dock reconsiderScreen(); if (!m_visibility) { m_visibility = new VisibilityManager(this); connect(m_visibility, &VisibilityManager::isHiddenChanged, this, [&]() { if (m_visibility->isHidden()) { deactivateApplets(); } }); } connect(this->containment(), SIGNAL(statusChanged(Plasma::Types::ItemStatus)), SLOT(statusChanged(Plasma::Types::ItemStatus))); }, Qt::DirectConnection); auto *latteCorona = qobject_cast(this->corona()); if (latteCorona) { connect(latteCorona, &Latte::Corona::viewLocationChanged, this, &View::dockLocationChanged); } } View::~View() { m_inDelete = true; disconnect(corona(), &Plasma::Corona::availableScreenRectChanged, this, &View::availableScreenRectChanged); disconnect(containment(), SIGNAL(statusChanged(Plasma::Types::ItemStatus)), this, SLOT(statusChanged(Plasma::Types::ItemStatus))); qDebug() << "dock view deleting..."; rootContext()->setContextProperty(QStringLiteral("dock"), nullptr); rootContext()->setContextProperty(QStringLiteral("themeExtended"), nullptr); rootContext()->setContextProperty(QStringLiteral("universalSettings"), nullptr); rootContext()->setContextProperty(QStringLiteral("layoutManager"), nullptr); //! this disconnect does not free up connections correctly when //! latteView is deleted. A crash for this example is the following: //! switch to Alternative Session and disable compositing, //! the signal creating the crash was probably from deleted //! windows. //! this->disconnect(); if (m_configView) { m_configView->setVisible(false);//hide(); } if (m_contextMenu) { delete m_contextMenu; } //needs to be deleted before Effects becuase it catches some of its signals if (m_positioner) { delete m_positioner; } if (m_effects) { delete m_effects; } if (m_visibility) delete m_visibility; } void View::init() { connect(this, &QQuickWindow::xChanged, this, &View::xChanged); connect(this, &QQuickWindow::xChanged, this, &View::updateAbsDockGeometry); connect(this, &QQuickWindow::yChanged, this, &View::yChanged); connect(this, &QQuickWindow::yChanged, this, &View::updateAbsDockGeometry); connect(this, &QQuickWindow::widthChanged, this, &View::widthChanged); connect(this, &QQuickWindow::widthChanged, this, &View::updateAbsDockGeometry); connect(this, &QQuickWindow::heightChanged, this, &View::heightChanged); connect(this, &QQuickWindow::heightChanged, this, &View::updateAbsDockGeometry); connect(corona(), &Plasma::Corona::availableScreenRectChanged, this, &View::availableScreenRectChanged); connect(this, &View::byPassWMChanged, this, &View::saveConfig); connect(this, &View::onPrimaryChanged, this, &View::saveConfig); connect(this, &View::isPreferredForShortcutsChanged, this, &View::saveConfig); connect(this, SIGNAL(normalThicknessChanged()), corona(), SIGNAL(availableScreenRectChanged())); connect(m_positioner, &ViewPart::Positioner::onHideWindowsForSlidingOut, this, &View::hideWindowsForSlidingOut); connect(m_positioner, &ViewPart::Positioner::screenGeometryChanged, this, &View::screenGeometryChanged); connect(m_contextMenu, &ViewPart::ContextMenu::menuChanged, this, &View::contextMenuIsShownChanged); ///!!!!! rootContext()->setContextProperty(QStringLiteral("dock"), this); auto *latteCorona = qobject_cast(this->corona()); if (latteCorona) { rootContext()->setContextProperty(QStringLiteral("universalSettings"), latteCorona->universalSettings()); rootContext()->setContextProperty(QStringLiteral("layoutManager"), latteCorona->layoutManager()); rootContext()->setContextProperty(QStringLiteral("themeExtended"), latteCorona->themeExtended()); } setSource(corona()->kPackage().filePath("lattedockui")); // setVisible(true); m_positioner->syncGeometry(); if (!KWindowSystem::isPlatformWayland()) { setVisible(true); } qDebug() << "SOURCE:" << source(); } bool View::inDelete() const { return m_inDelete; } void View::disconnectSensitiveSignals() { disconnect(corona(), &Plasma::Corona::availableScreenRectChanged, this, &View::availableScreenRectChanged); setManagedLayout(nullptr); if (visibility()) { visibility()->setEnabledDynamicBackground(false); } } void View::availableScreenRectChanged() { if (m_inDelete) return; if (formFactor() == Plasma::Types::Vertical) { m_positioner->syncGeometry(); } } void View::setupWaylandIntegration() { if (m_shellSurface) return; if (Latte::Corona *c = qobject_cast(corona())) { using namespace KWayland::Client; PlasmaShell *interface {c->waylandCoronaInterface()}; if (!interface) return; Surface *s{Surface::fromWindow(this)}; if (!s) return; m_shellSurface = interface->createSurface(s, this); qDebug() << "WAYLAND dock window surface was created..."; m_shellSurface->setSkipTaskbar(true); m_shellSurface->setRole(PlasmaShellSurface::Role::Panel); m_shellSurface->setPanelBehavior(PlasmaShellSurface::PanelBehavior::WindowsGoBelow); } } KWayland::Client::PlasmaShellSurface *View::surface() { return m_shellSurface; } //! the main function which decides if this dock is at the //! correct screen void View::reconsiderScreen() { m_positioner->reconsiderScreen(); } void View::copyView() { m_managedLayout->copyView(containment()); } void View::removeView() { if (m_managedLayout && m_managedLayout->viewsCount() > 1) { QAction *removeAct = this->containment()->actions()->action(QStringLiteral("remove")); if (removeAct) { removeAct->trigger(); } } } bool View::settingsWindowIsShown() { auto configView = qobject_cast(m_configView); return (configView != nullptr); } void View::showSettingsWindow() { showConfigurationInterface(containment()); applyActivitiesToWindows(); } void View::showConfigurationInterface(Plasma::Applet *applet) { if (!applet || !applet->containment()) return; Plasma::Containment *c = qobject_cast(applet); if (m_configView && c && c->isContainment() && c == this->containment()) { if (m_configView->isVisible()) { m_configView->setVisible(false); //m_configView->hide(); } else { m_configView->setVisible(true); //m_configView->show(); } return; } else if (m_configView) { if (m_configView->applet() == applet) { m_configView->setVisible(true); //m_configView->show(); m_configView->requestActivate(); return; } else { m_configView->setVisible(false); //m_configView->hide(); m_configView->deleteLater(); } } bool delayConfigView = false; if (c && containment() && c->isContainment() && c->id() == this->containment()->id()) { m_configView = new DockConfigView(c, this); delayConfigView = true; } else { m_configView = new PlasmaQuick::ConfigView(applet); } m_configView.data()->init(); if (!delayConfigView) { m_configView->setVisible(true); //m_configView.data()->show(); } else { //add a timer for showing the configuration window the first time it is //created in order to give the containmnent's layouts the time to //calculate the window's height if (!KWindowSystem::isPlatformWayland()) { QTimer::singleShot(150, m_configView, SLOT(show())); } else { QTimer::singleShot(150, [this]() { m_configView->setVisible(true); }); } } } QRect View::localGeometry() const { return m_localGeometry; } void View::setLocalGeometry(const QRect &geometry) { if (m_localGeometry == geometry) { return; } m_localGeometry = geometry; emit localGeometryChanged(); updateAbsDockGeometry(); } void View::updateAbsDockGeometry(bool bypassChecks) { //! there was a -1 in height and width here. The reason of this //! if I remember correctly was related to multi-screen but I cant //! remember exactly the reason, something related to rigth edge in //! multi screen environment. BUT this was breaking the entire AlwaysVisible //! experience with struts. Removing them in order to restore correct //! behavior and keeping this comment in order to check for //! multi-screen breakage QRect absGeometry {x() + m_localGeometry.x(), y() + m_localGeometry.y() , m_localGeometry.width(), m_localGeometry.height()}; if (m_absGeometry == absGeometry && !bypassChecks) return; m_absGeometry = absGeometry; emit absGeometryChanged(m_absGeometry); //! this is needed in order to update correctly the screenGeometries - if (visibility() && corona() && visibility()->mode() == Dock::AlwaysVisible) { + if (visibility() && corona() && visibility()->mode() == Types::AlwaysVisible) { emit corona()->availableScreenRectChanged(); emit corona()->availableScreenRegionChanged(); } } void View::statusChanged(Plasma::Types::ItemStatus status) { if (containment()) { if (containment()->status() >= Plasma::Types::NeedsAttentionStatus && containment()->status() != Plasma::Types::HiddenStatus) { setBlockHiding(true); } else { setBlockHiding(false); } } } bool View::alternativesIsShown() const { return m_alternativesIsShown; } void View::setAlternativesIsShown(bool show) { if (m_alternativesIsShown == show) { return; } m_alternativesIsShown = show; setBlockHiding(show); emit alternativesIsShownChanged(); } bool View::contextMenuIsShown() const { if (!m_contextMenu) { return false; } return m_contextMenu->menu(); } int View::currentThickness() const { if (formFactor() == Plasma::Types::Vertical) { return m_effects->mask().isNull() ? width() : m_effects->mask().width() - m_effects->innerShadow(); } else { return m_effects->mask().isNull() ? height() : m_effects->mask().height() - m_effects->innerShadow(); } } int View::normalThickness() const { return m_normalThickness; } void View::setNormalThickness(int thickness) { if (m_normalThickness == thickness) { return; } m_normalThickness = thickness; emit normalThicknessChanged(); } bool View::byPassWM() const { return m_byPassWM; } void View::setByPassWM(bool bypass) { if (m_byPassWM == bypass) { return; } m_byPassWM = bypass; emit byPassWMChanged(); } bool View::behaveAsPlasmaPanel() const { return m_behaveAsPlasmaPanel; } void View::setBehaveAsPlasmaPanel(bool behavior) { if (m_behaveAsPlasmaPanel == behavior) { return; } m_behaveAsPlasmaPanel = behavior; emit behaveAsPlasmaPanelChanged(); } bool View::inEditMode() const { return m_inEditMode; } void View::setInEditMode(bool edit) { if (m_inEditMode == edit) { return; } m_inEditMode = edit; emit inEditModeChanged(); } bool View::isPreferredForShortcuts() const { return m_isPreferredForShortcuts; } void View::setIsPreferredForShortcuts(bool preferred) { if (m_isPreferredForShortcuts == preferred) { return; } m_isPreferredForShortcuts = preferred; emit isPreferredForShortcutsChanged(); if (m_isPreferredForShortcuts && m_managedLayout) { emit m_managedLayout->preferredViewForShortcutsChanged(this); } } void View::preferredViewForShortcutsChangedSlot(Latte::View *view) { if (view != this) { setIsPreferredForShortcuts(false); } } bool View::onPrimary() const { return m_onPrimary; } void View::setOnPrimary(bool flag) { if (m_onPrimary == flag) { return; } m_onPrimary = flag; emit onPrimaryChanged(); } float View::maxLength() const { return m_maxLength; } void View::setMaxLength(float length) { if (m_maxLength == length) { return; } m_maxLength = length; emit maxLengthChanged(); } int View::maxThickness() const { return m_maxThickness; } void View::setMaxThickness(int thickness) { if (m_maxThickness == thickness) return; m_maxThickness = thickness; emit maxThicknessChanged(); } int View::alignment() const { return m_alignment; } void View::setAlignment(int alignment) { - Dock::Alignment align = static_cast(alignment); + Types::Alignment align = static_cast(alignment); if (m_alignment == alignment) { return; } m_alignment = align; emit alignmentChanged(); } QRect View::absGeometry() const { return m_absGeometry; } QRect View::screenGeometry() const { if (this->screen()) { QRect geom = this->screen()->geometry(); return geom; } return QRect(); } int View::offset() const { return m_offset; } void View::setOffset(int offset) { if (m_offset == offset) { return; } m_offset = offset; emit offsetChanged(); } int View::fontPixelSize() const { return m_fontPixelSize; } void View::setFontPixelSize(int size) { if (m_fontPixelSize == size) { return; } m_fontPixelSize = size; emit fontPixelSizeChanged(); } void View::applyActivitiesToWindows() { if (m_visibility) { QStringList activities = m_managedLayout->appliedActivities(); m_visibility->setWindowOnActivities(*this, activities); if (m_configView) { m_visibility->setWindowOnActivities(*m_configView, activities); auto configView = qobject_cast(m_configView); if (configView && configView->secondaryWindow()) { m_visibility->setWindowOnActivities(*configView->secondaryWindow(), activities); } } if (m_visibility->supportsKWinEdges()) { m_visibility->applyActivitiesToHiddenWindows(activities); } } } Layout *View::managedLayout() const { return m_managedLayout; } void View::setManagedLayout(Layout *layout) { if (m_managedLayout == layout) { return; } // clear mode for (auto &c : connectionsManagedLayout) { disconnect(c); } m_managedLayout = layout; if (m_managedLayout) { //! Sometimes the activity isnt completely ready, by adding a delay //! we try to catch up QTimer::singleShot(100, [this]() { if (m_managedLayout && m_visibility) { qDebug() << "DOCK VIEW FROM LAYOUT ::: " << m_managedLayout->name() << " - activities: " << m_managedLayout->appliedActivities(); applyActivitiesToWindows(); emit activitiesChanged(); } }); connectionsManagedLayout[0] = connect(m_managedLayout, &Layout::preferredViewForShortcutsChanged, this, &View::preferredViewForShortcutsChangedSlot); } Latte::Corona *latteCorona = qobject_cast(this->corona()); - if (latteCorona->layoutManager()->memoryUsage() == Dock::MultipleLayouts) { + if (latteCorona->layoutManager()->memoryUsage() == Types::MultipleLayouts) { connectionsManagedLayout[1] = connect(latteCorona->activitiesConsumer(), &KActivities::Consumer::runningActivitiesChanged, this, [&]() { if (m_managedLayout && m_visibility) { qDebug() << "DOCK VIEW FROM LAYOUT (runningActivitiesChanged) ::: " << m_managedLayout->name() << " - activities: " << m_managedLayout->appliedActivities(); applyActivitiesToWindows(); emit activitiesChanged(); } }); connectionsManagedLayout[2] = connect(m_managedLayout, &Layout::activitiesChanged, this, [&]() { if (m_managedLayout) { applyActivitiesToWindows(); emit activitiesChanged(); } }); connectionsManagedLayout[3] = connect(latteCorona->layoutManager(), &LayoutManager::layoutsChanged, this, [&]() { if (m_managedLayout) { applyActivitiesToWindows(); emit activitiesChanged(); } }); //!IMPORTANT!!! ::: This fixes a bug when closing an Activity all docks from all Activities are //! disappearing! With this they reappear!!! connectionsManagedLayout[4] = connect(this, &QWindow::visibleChanged, this, [&]() { if (!isVisible() && m_managedLayout) { QTimer::singleShot(100, [this]() { if (m_managedLayout && containment() && !containment()->destroyed()) { setVisible(true); applyActivitiesToWindows(); emit activitiesChanged(); } }); QTimer::singleShot(1500, [this]() { if (m_managedLayout && containment() && !containment()->destroyed()) { setVisible(true); applyActivitiesToWindows(); emit activitiesChanged(); } }); } }); } emit managedLayoutChanged(); } void View::moveToLayout(QString layoutName) { if (!m_managedLayout) { return; } QList containments = m_managedLayout->unassignFromLayout(this); Latte::Corona *latteCorona = qobject_cast(this->corona()); if (latteCorona && containments.size() > 0) { Layout *newLayout = latteCorona->layoutManager()->activeLayout(layoutName); if (newLayout) { newLayout->assignToLayout(this, containments); } } } void View::setBlockHiding(bool block) { if (!block) { auto *configView = qobject_cast(m_configView); if (m_alternativesIsShown || (configView && configView->sticker() && configView->isVisible())) { return; } if (m_visibility) { m_visibility->setBlockHiding(false); } } else { if (m_visibility) { m_visibility->setBlockHiding(true); } } } void View::hideWindowsForSlidingOut() { setBlockHiding(false); if (m_configView) { auto configDialog = qobject_cast(m_configView); if (configDialog) { configDialog->hideConfigWindow(); } } } //! remove latte tasks plasmoid void View::removeTasksPlasmoid() { if (!tasksPresent() || !containment()) { return; } foreach (Plasma::Applet *applet, containment()->applets()) { KPluginMetaData meta = applet->kPackage().metadata(); if (meta.pluginId() == "org.kde.latte.plasmoid") { QAction *closeApplet = applet->actions()->action(QStringLiteral("remove")); if (closeApplet) { closeApplet->trigger(); //! remove only the first found return; } } } } //! check if the tasks plasmoid exist in the dock bool View::tasksPresent() { if (!this->containment()) { return false; } foreach (Plasma::Applet *applet, this->containment()->applets()) { const auto &provides = KPluginMetaData::readStringList(applet->pluginMetaData().rawData(), QStringLiteral("X-Plasma-Provides")); if (provides.contains(QLatin1String("org.kde.plasma.multitasking"))) { return true; } } return false; } //! check if the tasks plasmoid exist in the dock bool View::latteTasksPresent() { if (!this->containment()) { return false; } foreach (Plasma::Applet *applet, this->containment()->applets()) { KPluginMetaData metadata = applet->pluginMetaData(); if (metadata.pluginId() == "org.kde.latte.plasmoid") { return true; } } return false; } //!check if the plasmoid with _name_ exists in the midedata bool View::mimeContainsPlasmoid(QMimeData *mimeData, QString name) { if (!mimeData) { return false; } if (mimeData->hasFormat(QStringLiteral("text/x-plasmoidservicename"))) { QString data = mimeData->data(QStringLiteral("text/x-plasmoidservicename")); const QStringList appletNames = data.split('\n', QString::SkipEmptyParts); foreach (const QString &appletName, appletNames) { if (appletName == name) return true; } } return false; } ViewPart::Effects *View::effects() const { return m_effects; } ViewPart::Positioner *View::positioner() const { return m_positioner; } VisibilityManager *View::visibility() const { return m_visibility; } bool View::event(QEvent *e) { if (!m_inDelete) { emit eventTriggered(e); switch (e->type()) { case QEvent::Leave: engine()->trimComponentCache(); break; case QEvent::PlatformSurface: if (auto pe = dynamic_cast(e)) { switch (pe->surfaceEventType()) { case QPlatformSurfaceEvent::SurfaceCreated: setupWaylandIntegration(); if (m_shellSurface) { m_positioner->syncGeometry(); m_effects->updateShadows(); } break; case QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed: if (m_shellSurface) { delete m_shellSurface; m_shellSurface = nullptr; qDebug() << "WAYLAND dock window surface was deleted..."; m_effects->clearShadows(); } break; } } break; default: break; } } return ContainmentView::event(e);; } void View::deactivateApplets() { if (!containment()) { return; } foreach (auto applet, containment()->applets()) { PlasmaQuick::AppletQuickItem *ai = applet->property("_plasma_graphicObject").value(); if (ai) { ai->setExpanded(false); } } } void View::toggleAppletExpanded(const int id) { if (!containment()) { return; } foreach (auto applet, containment()->applets()) { if (applet->id() == id) { PlasmaQuick::AppletQuickItem *ai = applet->property("_plasma_graphicObject").value(); if (ai) { if (!ai->isActivationTogglesExpanded()) { ai->setActivationTogglesExpanded(true); } emit applet->activated(); } } } } QVariantList View::containmentActions() { QVariantList actions; /*if (containment()->corona()->immutability() != Plasma::Types::Mutable) { return actions; }*/ //FIXME: the trigger string it should be better to be supported this way //const QString trigger = Plasma::ContainmentActions::eventToString(event); const QString trigger = "RightButton;NoModifier"; Plasma::ContainmentActions *plugin = this->containment()->containmentActions().value(trigger); if (!plugin) { return actions; } if (plugin->containment() != this->containment()) { plugin->setContainment(this->containment()); // now configure it KConfigGroup cfg(this->containment()->corona()->config(), "ActionPlugins"); cfg = KConfigGroup(&cfg, QString::number(this->containment()->containmentType())); KConfigGroup pluginConfig = KConfigGroup(&cfg, trigger); plugin->restore(pluginConfig); } foreach (QAction *ac, plugin->contextualActions()) { actions << QVariant::fromValue(ac); } return actions; } void View::disableGrabItemBehavior() { setMouseGrabEnabled(false); } void View::restoreGrabItemBehavior() { setMouseGrabEnabled(true); if (mouseGrabberItem()) { mouseGrabberItem()->ungrabMouse(); } } //!BEGIN overriding context menus behavior void View::mousePressEvent(QMouseEvent *event) { bool result = m_contextMenu->mousePressEvent(event); emit contextMenuIsShownChanged(); if (result) { PlasmaQuick::ContainmentView::mousePressEvent(event); } } //!END overriding context menus behavior //!BEGIN configuration functions void View::saveConfig() { if (!this->containment()) return; auto config = this->containment()->config(); config.writeEntry("onPrimary", onPrimary()); config.writeEntry("byPassWM", byPassWM()); config.writeEntry("isPreferredForShortcuts", isPreferredForShortcuts()); config.sync(); } void View::restoreConfig() { if (!this->containment()) return; auto config = this->containment()->config(); m_onPrimary = config.readEntry("onPrimary", true); m_byPassWM = config.readEntry("byPassWM", false); m_isPreferredForShortcuts = config.readEntry("isPreferredForShortcuts", false); //! Send changed signals at the end in order to be sure that saveConfig //! wont rewrite default/invalid values emit onPrimaryChanged(); emit byPassWMChanged(); } //!END configuration functions } //!END namespace diff --git a/app/view/view.h b/app/view/view.h index cd15cc11..812f9ada 100644 --- a/app/view/view.h +++ b/app/view/view.h @@ -1,286 +1,286 @@ /* * 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 . */ #ifndef VIEW_H #define VIEW_H // local #include "dockconfigview.h" #include "effects.h" #include "positioner.h" #include "visibilitymanager.h" #include "../layout.h" #include "../plasmaquick/containmentview.h" #include "../plasmaquick/configview.h" -#include "../../liblattedock/dock.h" +#include "../../liblatte2/types.h" // C++ #include // Qt #include #include #include #include #include #include namespace Plasma { class Types; class Corona; class Containment; } namespace KWayland { namespace Client { class PlasmaShellSurface; } } namespace Latte { class Layout; namespace ViewPart { class ContextMenu; } } namespace Latte { class View : public PlasmaQuick::ContainmentView { Q_OBJECT Q_PROPERTY(bool alternativesIsShown READ alternativesIsShown NOTIFY alternativesIsShownChanged) Q_PROPERTY(bool behaveAsPlasmaPanel READ behaveAsPlasmaPanel WRITE setBehaveAsPlasmaPanel NOTIFY behaveAsPlasmaPanelChanged) Q_PROPERTY(bool byPassWM READ byPassWM WRITE setByPassWM NOTIFY byPassWMChanged) Q_PROPERTY(bool contextMenuIsShown READ contextMenuIsShown NOTIFY contextMenuIsShownChanged) //! Because Latte uses animations, changing to edit mode it may be different than //! when the isUserConfiguring changes value Q_PROPERTY(bool inEditMode READ inEditMode WRITE setInEditMode NOTIFY inEditModeChanged) Q_PROPERTY(bool isPreferredForShortcuts READ isPreferredForShortcuts WRITE setIsPreferredForShortcuts NOTIFY isPreferredForShortcutsChanged) Q_PROPERTY(bool onPrimary READ onPrimary WRITE setOnPrimary NOTIFY onPrimaryChanged) Q_PROPERTY(int alignment READ alignment WRITE setAlignment NOTIFY alignmentChanged) Q_PROPERTY(int fontPixelSize READ fontPixelSize WRITE setFontPixelSize NOTIFY fontPixelSizeChanged) Q_PROPERTY(int x READ x NOTIFY xChanged) Q_PROPERTY(int y READ y NOTIFY yChanged) Q_PROPERTY(int width READ width NOTIFY widthChanged) Q_PROPERTY(int height READ height NOTIFY heightChanged) Q_PROPERTY(int maxThickness READ maxThickness WRITE setMaxThickness NOTIFY maxThicknessChanged) Q_PROPERTY(int normalThickness READ normalThickness WRITE setNormalThickness NOTIFY normalThicknessChanged) Q_PROPERTY(int offset READ offset WRITE setOffset NOTIFY offsetChanged) Q_PROPERTY(float maxLength READ maxLength WRITE setMaxLength NOTIFY maxLengthChanged) Q_PROPERTY(Latte::ViewPart::Effects *effects READ effects NOTIFY effectsChanged) Q_PROPERTY(Layout *managedLayout READ managedLayout WRITE setManagedLayout NOTIFY managedLayoutChanged) Q_PROPERTY(Latte::ViewPart::Positioner *positioner READ positioner NOTIFY positionerChanged) Q_PROPERTY(VisibilityManager *visibility READ visibility NOTIFY visibilityChanged) Q_PROPERTY(QRect absoluteGeometry READ absGeometry NOTIFY absGeometryChanged) Q_PROPERTY(QRect localGeometry READ localGeometry WRITE setLocalGeometry NOTIFY localGeometryChanged) Q_PROPERTY(QRect screenGeometry READ screenGeometry NOTIFY screenGeometryChanged) public: View(Plasma::Corona *corona, QScreen *targetScreen = nullptr, bool byPassWM = false); virtual ~View(); void init(); bool alternativesIsShown() const; void setAlternativesIsShown(bool show); bool inDelete() const; bool onPrimary() const; void setOnPrimary(bool flag); int currentThickness() const; bool behaveAsPlasmaPanel() const; void setBehaveAsPlasmaPanel(bool behavior); bool contextMenuIsShown() const; bool byPassWM() const; void setByPassWM(bool bypass); bool inEditMode() const; void setInEditMode(bool edit); bool isPreferredForShortcuts() const; void setIsPreferredForShortcuts(bool preferred); float maxLength() const; void setMaxLength(float length); int fontPixelSize() const; void setFontPixelSize(int size); int maxThickness() const; void setMaxThickness(int thickness); int normalThickness() const; void setNormalThickness(int thickness); int offset() const; void setOffset(int offset); int alignment() const; void setAlignment(int alignment); QRect absGeometry() const; QRect screenGeometry() const; QRect localGeometry() const; void setLocalGeometry(const QRect &geometry); bool settingsWindowIsShown(); void showSettingsWindow(); ViewPart::Effects *effects() const; ViewPart::Positioner *positioner() const; VisibilityManager *visibility() const; Layout *managedLayout() const; void setManagedLayout(Layout *layout); KWayland::Client::PlasmaShellSurface *surface(); void reconsiderScreen(); //! these are signals that create crashes, such a example is the availableScreenRectChanged from corona //! when its containment is destroyed void disconnectSensitiveSignals(); public slots: Q_INVOKABLE void copyView(); Q_INVOKABLE void removeView(); Q_INVOKABLE QVariantList containmentActions(); Q_INVOKABLE void deactivateApplets(); Q_INVOKABLE void moveToLayout(QString layoutName); Q_INVOKABLE void removeTasksPlasmoid(); Q_INVOKABLE void setBlockHiding(bool block); Q_INVOKABLE void toggleAppletExpanded(const int id); Q_INVOKABLE bool mimeContainsPlasmoid(QMimeData *mimeData, QString name); Q_INVOKABLE bool tasksPresent(); Q_INVOKABLE bool latteTasksPresent(); void updateAbsDockGeometry(bool bypassChecks = false); Q_INVOKABLE void disableGrabItemBehavior(); Q_INVOKABLE void restoreGrabItemBehavior(); protected slots: void showConfigurationInterface(Plasma::Applet *applet) override; protected: bool event(QEvent *ev) override; void mousePressEvent(QMouseEvent *event) override; signals: void addInternalViewSplitter(); void removeInternalViewSplitter(); void eventTriggered(QEvent *ev); void activitiesChanged(); void alternativesIsShownChanged(); void alignmentChanged(); void behaveAsPlasmaPanelChanged(); void byPassWMChanged(); void contextMenuIsShownChanged(); void dockLocationChanged(); void effectsChanged(); void fontPixelSizeChanged(); void widthChanged(); void heightChanged(); void inEditModeChanged(); void isPreferredForShortcutsChanged(); void localGeometryChanged(); void managedLayoutChanged(); void maxLengthChanged(); void maxThicknessChanged(); void normalThicknessChanged(); void offsetChanged(); void onPrimaryChanged(); void visibilityChanged(); void positionerChanged(); void screenGeometryChanged(); void xChanged(); void yChanged(); void absGeometryChanged(const QRect &geometry); private slots: void availableScreenRectChanged(); void hideWindowsForSlidingOut(); void preferredViewForShortcutsChangedSlot(Latte::View *view); void statusChanged(Plasma::Types::ItemStatus); void restoreConfig(); void saveConfig(); private: void applyActivitiesToWindows(); void initSignalingForLocationChangeSliding(); void setupWaylandIntegration(); void updateAppletContainsMethod(); private: Plasma::Containment *containmentById(uint id); bool m_alternativesIsShown{false}; bool m_behaveAsPlasmaPanel{false}; bool m_byPassWM{true}; bool m_inDelete{false}; bool m_inEditMode{false}; bool m_isPreferredForShortcuts{false}; bool m_onPrimary{true}; int m_fontPixelSize{ -1}; int m_maxThickness{24}; int m_normalThickness{24}; int m_offset{0}; float m_maxLength{1}; - Dock::Alignment m_alignment{Dock::Center}; + Types::Alignment m_alignment{Types::Center}; QRect m_localGeometry; QRect m_absGeometry; Layout *m_managedLayout{nullptr}; QPointer m_configView; QPointer m_contextMenu; QPointer m_effects; QPointer m_positioner; QPointer m_visibility; //! Connections to release and bound for the managed layout std::array connectionsManagedLayout; KWayland::Client::PlasmaShellSurface *m_shellSurface{nullptr}; }; } #endif diff --git a/app/view/visibilitymanager.cpp b/app/view/visibilitymanager.cpp index 996f859a..2a49d3c5 100644 --- a/app/view/visibilitymanager.cpp +++ b/app/view/visibilitymanager.cpp @@ -1,1254 +1,1254 @@ /* * 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 "visibilitymanager.h" #include "visibilitymanager_p.h" // local #include "positioner.h" #include "screenedgeghostwindow.h" #include "view.h" #include "../lattecorona.h" #include "../layoutmanager.h" #include "../screenpool.h" #include "../wm/windowinfowrap.h" -#include "../../liblattedock/extras.h" +#include "../../liblatte2/extras.h" // Qt #include // KDE #include #include namespace Latte { //! BEGIN: VisiblityManagerPrivate implementation VisibilityManagerPrivate::VisibilityManagerPrivate(PlasmaQuick::ContainmentView *view, VisibilityManager *q) : QObject(nullptr), q(q), view(view) { m_latteView = qobject_cast(view); m_corona = qobject_cast(view->corona()); wm = m_corona->wm(); if (m_latteView) { connect(m_latteView, &Latte::View::eventTriggered, this, &VisibilityManagerPrivate::viewEventManager); connect(m_latteView, &Latte::View::absGeometryChanged, this, &VisibilityManagerPrivate::setViewGeometry); } timerStartUp.setInterval(5000); timerStartUp.setSingleShot(true); timerCheckWindows.setInterval(350); timerCheckWindows.setSingleShot(true); timerShow.setSingleShot(true); timerHide.setSingleShot(true); connect(&timerCheckWindows, &QTimer::timeout, this, &VisibilityManagerPrivate::checkAllWindows); connect(&timerShow, &QTimer::timeout, this, [this, q]() { if (isHidden) { // qDebug() << "must be shown"; emit this->q->mustBeShown(VisibilityManager::QPrivateSignal{}); } }); connect(&timerHide, &QTimer::timeout, this, [this]() { if (!blockHiding && !isHidden && !dragEnter) { // qDebug() << "must be hide"; emit this->q->mustBeHide(VisibilityManager::QPrivateSignal{}); } }); wm->setViewExtraFlags(*view); wm->addView(view->winId()); restoreConfig(); } VisibilityManagerPrivate::~VisibilityManagerPrivate() { qDebug() << "VisibilityManagerPrivate deleting..."; wm->removeViewStruts(*view); wm->removeView(view->winId()); if (edgeGhostWindow) { edgeGhostWindow->deleteLater(); } } -inline void VisibilityManagerPrivate::setMode(Dock::Visibility mode) +inline void VisibilityManagerPrivate::setMode(Types::Visibility mode) { if (this->mode == mode) return; - Q_ASSERT_X(mode != Dock::None, q->staticMetaObject.className(), "set visibility to Dock::None"); + Q_ASSERT_X(mode != Types::None, q->staticMetaObject.className(), "set visibility to Types::None"); // clear mode for (auto &c : connections) { disconnect(c); } - if (mode != Dock::DodgeAllWindows && !enabledDynamicBackgroundFlag) { + if (mode != Types::DodgeAllWindows && !enabledDynamicBackgroundFlag) { windows.clear(); } - if (this->mode == Dock::AlwaysVisible) { + if (this->mode == Types::AlwaysVisible) { wm->removeViewStruts(*view); } else { connections[3] = connect(wm, &WindowSystem::currentDesktopChanged , this, [&] { if (raiseOnDesktopChange) raiseViewTemporarily(); }); connections[4] = connect(wm, &WindowSystem::currentActivityChanged , this, [&]() { if (raiseOnActivityChange) raiseViewTemporarily(); else updateHiddenState(); }); } timerShow.stop(); timerHide.stop(); timerCheckWindows.stop(); this->mode = mode; switch (this->mode) { - case Dock::AlwaysVisible: { + case Types::AlwaysVisible: { //set wayland visibility mode if (m_latteView->surface()) { m_latteView->surface()->setPanelBehavior(KWayland::Client::PlasmaShellSurface::PanelBehavior::WindowsGoBelow); } if (view->containment() && !m_latteView->inEditMode() && view->screen()) { updateStrutsBasedOnLayoutsAndActivities(); } connections[0] = connect(view->containment(), &Plasma::Containment::locationChanged , this, [&]() { if (m_latteView->inEditMode()) wm->removeViewStruts(*view); }); connections[1] = connect(m_latteView, &Latte::View::inEditModeChanged , this, [&]() { if (!m_latteView->inEditMode() && !m_latteView->positioner()->inLocationChangeAnimation() && view->screen()) wm->setViewStruts(*view, m_viewGeometry, view->containment()->location()); }); - if (m_corona && m_corona->layoutManager()->memoryUsage() == Dock::MultipleLayouts) { + if (m_corona && m_corona->layoutManager()->memoryUsage() == Types::MultipleLayouts) { connections[2] = connect(m_corona->activitiesConsumer(), &KActivities::Consumer::currentActivityChanged, this, [&]() { updateStrutsBasedOnLayoutsAndActivities(); }); connections[3] = connect(m_latteView, &Latte::View::activitiesChanged, this, [&]() { updateStrutsBasedOnLayoutsAndActivities(); }); } raiseView(true); } break; - case Dock::AutoHide: { + case Types::AutoHide: { //set wayland visibility mode if (m_latteView->surface()) { m_latteView->surface()->setPanelBehavior(KWayland::Client::PlasmaShellSurface::PanelBehavior::AutoHide); } raiseView(containsMouse); } break; - case Dock::DodgeActive: { + case Types::DodgeActive: { //set wayland visibility mode if (m_latteView->surface()) { m_latteView->surface()->setPanelBehavior(KWayland::Client::PlasmaShellSurface::PanelBehavior::AutoHide); } connections[0] = connect(wm, &WindowSystem::activeWindowChanged , this, &VisibilityManagerPrivate::dodgeActive); connections[1] = connect(wm, &WindowSystem::windowChanged , this, &VisibilityManagerPrivate::dodgeActive); dodgeActive(wm->activeWindow()); } break; - case Dock::DodgeMaximized: { + case Types::DodgeMaximized: { //set wayland visibility mode if (m_latteView->surface()) { m_latteView->surface()->setPanelBehavior(KWayland::Client::PlasmaShellSurface::PanelBehavior::AutoHide); } connections[0] = connect(wm, &WindowSystem::activeWindowChanged , this, &VisibilityManagerPrivate::dodgeMaximized); connections[1] = connect(wm, &WindowSystem::windowChanged , this, &VisibilityManagerPrivate::dodgeMaximized); dodgeMaximized(wm->activeWindow()); } break; - case Dock::DodgeAllWindows: { + case Types::DodgeAllWindows: { //set wayland visibility mode if (m_latteView->surface()) { m_latteView->surface()->setPanelBehavior(KWayland::Client::PlasmaShellSurface::PanelBehavior::AutoHide); } for (const auto &wid : wm->windows()) { windows.insert(wid, wm->requestInfo(wid)); } connections[0] = connect(wm, &WindowSystem::windowChanged , this, &VisibilityManagerPrivate::dodgeWindows); connections[1] = connect(wm, &WindowSystem::windowRemoved , this, [&](WindowId wid) { windows.remove(wid); timerCheckWindows.start(); }); connections[2] = connect(wm, &WindowSystem::windowAdded , this, [&](WindowId wid) { windows.insert(wid, wm->requestInfo(wid)); timerCheckWindows.start(); }); timerCheckWindows.start(); } break; - case Dock::WindowsGoBelow: + case Types::WindowsGoBelow: //set wayland visibility mode if (m_latteView->surface()) { m_latteView->surface()->setPanelBehavior(KWayland::Client::PlasmaShellSurface::PanelBehavior::WindowsGoBelow); } break; default: break; } view->containment()->config().writeEntry("visibility", static_cast(mode)); updateKWinEdgesSupport(); emit q->modeChanged(); } void VisibilityManagerPrivate::updateStrutsBasedOnLayoutsAndActivities() { - bool multipleLayoutsAndCurrent = (m_corona->layoutManager()->memoryUsage() == Dock::MultipleLayouts + bool multipleLayoutsAndCurrent = (m_corona->layoutManager()->memoryUsage() == Types::MultipleLayouts && m_latteView->managedLayout() && !m_latteView->positioner()->inLocationChangeAnimation() && m_latteView->managedLayout()->name() == m_corona->layoutManager()->currentLayoutName()); - if (m_corona->layoutManager()->memoryUsage() == Dock::SingleLayout || multipleLayoutsAndCurrent) { + if (m_corona->layoutManager()->memoryUsage() == Types::SingleLayout || multipleLayoutsAndCurrent) { wm->setViewStruts(*view, m_viewGeometry, view->location()); } else { wm->removeViewStruts(*view); } } void VisibilityManagerPrivate::setRaiseOnDesktop(bool enable) { if (enable == raiseOnDesktopChange) return; raiseOnDesktopChange = enable; emit q->raiseOnDesktopChanged(); } void VisibilityManagerPrivate::setRaiseOnActivity(bool enable) { if (enable == raiseOnActivityChange) return; raiseOnActivityChange = enable; emit q->raiseOnActivityChanged(); } inline void VisibilityManagerPrivate::setIsHidden(bool isHidden) { if (this->isHidden == isHidden) return; if (blockHiding && isHidden) { qWarning() << "isHidden property is blocked, ignoring update"; return; } this->isHidden = isHidden; if (q->supportsKWinEdges()) { - bool inCurrentLayout = (m_corona->layoutManager()->memoryUsage() == Dock::SingleLayout || - (m_corona->layoutManager()->memoryUsage() == Dock::MultipleLayouts + bool inCurrentLayout = (m_corona->layoutManager()->memoryUsage() == Types::SingleLayout || + (m_corona->layoutManager()->memoryUsage() == Types::MultipleLayouts && m_latteView->managedLayout() && !m_latteView->positioner()->inLocationChangeAnimation() && m_latteView->managedLayout()->name() == m_corona->layoutManager()->currentLayoutName())); if (inCurrentLayout) { wm->setEdgeStateFor(edgeGhostWindow, isHidden); } else { wm->setEdgeStateFor(edgeGhostWindow, false); } } emit q->isHiddenChanged(); } void VisibilityManagerPrivate::setBlockHiding(bool blockHiding) { if (this->blockHiding == blockHiding) return; this->blockHiding = blockHiding; // qDebug() << "blockHiding:" << blockHiding; if (this->blockHiding) { timerHide.stop(); if (isHidden) { emit q->mustBeShown(VisibilityManager::QPrivateSignal{}); } } else { updateHiddenState(); } emit q->blockHidingChanged(); } inline void VisibilityManagerPrivate::setTimerShow(int msec) { timerShow.setInterval(msec); emit q->timerShowChanged(); } inline void VisibilityManagerPrivate::setTimerHide(int msec) { timerHide.setInterval(msec); emit q->timerHideChanged(); } inline void VisibilityManagerPrivate::raiseView(bool raise) { if (blockHiding) return; if (raise) { timerHide.stop(); if (!timerShow.isActive()) { timerShow.start(); } } else if (!dragEnter) { timerShow.stop(); if (hideNow) { hideNow = false; emit q->mustBeHide(VisibilityManager::QPrivateSignal{}); } else if (!timerHide.isActive()) { timerHide.start(); } } } void VisibilityManagerPrivate::raiseViewTemporarily() { if (raiseTemporarily) return; raiseTemporarily = true; timerHide.stop(); timerShow.stop(); if (isHidden) emit q->mustBeShown(VisibilityManager::QPrivateSignal{}); QTimer::singleShot(qBound(1800, 2 * timerHide.interval(), 3000), this, [&]() { raiseTemporarily = false; hideNow = true; updateHiddenState(); }); } void VisibilityManagerPrivate::updateHiddenState() { if (dragEnter) return; switch (mode) { - case Dock::AutoHide: + case Types::AutoHide: raiseView(containsMouse); break; - case Dock::DodgeActive: + case Types::DodgeActive: dodgeActive(wm->activeWindow()); break; - case Dock::DodgeMaximized: + case Types::DodgeMaximized: dodgeMaximized(wm->activeWindow()); break; - case Dock::DodgeAllWindows: + case Types::DodgeAllWindows: dodgeWindows(wm->activeWindow()); break; default: break; } } inline void VisibilityManagerPrivate::setViewGeometry(const QRect &geometry) { if (!view->containment()) return; m_viewGeometry = geometry; - if (mode == Dock::AlwaysVisible && !m_latteView->inEditMode() && view->screen()) { + if (mode == Types::AlwaysVisible && !m_latteView->inEditMode() && view->screen()) { updateStrutsBasedOnLayoutsAndActivities(); } } void VisibilityManagerPrivate::setWindowOnActivities(QWindow &window, const QStringList &activities) { wm->setWindowOnActivities(window, activities); } void VisibilityManagerPrivate::applyActivitiesToHiddenWindows(const QStringList &activities) { if (edgeGhostWindow) { wm->setWindowOnActivities(*edgeGhostWindow, activities); } } void VisibilityManagerPrivate::dodgeActive(WindowId wid) { if (raiseTemporarily) return; //!don't send false raiseView signal when containing mouse if (containsMouse) { raiseView(true); return; } auto winfo = wm->requestInfo(wid); if (!winfo.isValid() || !winfo.isActive()) { winfo = wm->requestInfo(wm->activeWindow()); if (!winfo.isValid()) { //! very rare case that window manager doesnt have any active window at all raiseView(true); return; } } //! don't send false raiseView signal when containing mouse, // Johan comment //! I dont know why that wasnt winfo.wid() //active window, but just wid//the window that made the call if (wm->isOnCurrentDesktop(winfo.wid()) && wm->isOnCurrentActivity(winfo.wid())) { bool overlaps{intersects(winfo)}; raiseView(!overlaps); } } void VisibilityManagerPrivate::dodgeMaximized(WindowId wid) { if (raiseTemporarily) return; //!don't send false raiseView signal when containing mouse if (containsMouse) { raiseView(true); return; } auto winfo = wm->requestInfo(wid); if (!winfo.isValid() || !winfo.isActive()) { winfo = wm->requestInfo(wm->activeWindow()); if (!winfo.isValid()) { //! very rare case that window manager doesnt have any active window at all raiseView(true); return; } } auto intersectsMaxVert = [&]() noexcept -> bool { return ((winfo.isMaxVert() || (view->screen() && view->screen()->availableSize().height() <= winfo.geometry().height())) && intersects(winfo)); }; auto intersectsMaxHoriz = [&]() noexcept -> bool { return ((winfo.isMaxHoriz() || (view->screen() && view->screen()->availableSize().width() <= winfo.geometry().width())) && intersects(winfo)); }; //! don't send false raiseView signal when containing mouse, // Johan comment //! I dont know why that wasnt winfo.wid() //active window, but just wid//the window that made the call if (wm->isOnCurrentDesktop(winfo.wid()) && wm->isOnCurrentActivity(winfo.wid())) { bool overlapsMaximized{view->formFactor() == Plasma::Types::Vertical ? intersectsMaxHoriz() : intersectsMaxVert()}; raiseView(!overlapsMaximized); } } void VisibilityManagerPrivate::dodgeWindows(WindowId wid) { if (raiseTemporarily) return; if (windows.find(wid) == std::end(windows)) return; //!don't send false raiseView signal when containing mouse if (containsMouse) { raiseView(true); return; } windows[wid] = wm->requestInfo(wid); auto &winfo = windows[wid]; if (!winfo.isValid() || !wm->isOnCurrentDesktop(wid) || !wm->isOnCurrentActivity(wid)) return; if (intersects(winfo)) raiseView(false); else timerCheckWindows.start(); } void VisibilityManagerPrivate::checkAllWindows() { if (raiseTemporarily) return; bool raise{true}; bool existsFaultyWindow{false}; for (const auto &winfo : windows) { // if (winfo.geometry() == QRect(0, 0, 0, 0)) { existsFaultyWindow = true; } if (!winfo.isValid() || !wm->isOnCurrentDesktop(winfo.wid()) || !wm->isOnCurrentActivity(winfo.wid())) continue; if (winfo.isFullscreen()) { raise = false; break; } else if (intersects(winfo)) { raise = false; break; } } cleanupFaultyWindows(); raiseView(raise); } inline bool VisibilityManagerPrivate::intersects(const WindowInfoWrap &winfo) { return (!winfo.isMinimized() && winfo.geometry().intersects(m_viewGeometry) && !winfo.isShaded()); } inline void VisibilityManagerPrivate::saveConfig() { if (!view->containment()) return; auto config = view->containment()->config(); config.writeEntry("enableKWinEdges", enableKWinEdgesFromUser); config.writeEntry("timerShow", timerShow.interval()); config.writeEntry("timerHide", timerHide.interval()); config.writeEntry("raiseOnDesktopChange", raiseOnDesktopChange); config.writeEntry("raiseOnActivityChange", raiseOnActivityChange); view->containment()->configNeedsSaving(); } inline void VisibilityManagerPrivate::restoreConfig() { if (!view->containment()) return; auto config = view->containment()->config(); timerShow.setInterval(config.readEntry("timerShow", 0)); timerHide.setInterval(config.readEntry("timerHide", 700)); emit q->timerShowChanged(); emit q->timerHideChanged(); enableKWinEdgesFromUser = config.readEntry("enableKWinEdges", true); emit q->enableKWinEdgesChanged(); setRaiseOnDesktop(config.readEntry("raiseOnDesktopChange", false)); setRaiseOnActivity(config.readEntry("raiseOnActivityChange", false)); auto mode = [&]() { - return static_cast(view->containment()->config() - .readEntry("visibility", static_cast(Dock::DodgeActive))); + return static_cast(view->containment()->config() + .readEntry("visibility", static_cast(Types::DodgeActive))); }; - if (mode() == Dock::AlwaysVisible) { - setMode(Dock::AlwaysVisible); + if (mode() == Types::AlwaysVisible) { + setMode(Types::AlwaysVisible); } else { connect(&timerStartUp, &QTimer::timeout, this, [ &, mode]() { setMode(mode()); }); connect(view->containment(), &Plasma::Containment::userConfiguringChanged , this, [&](bool configuring) { if (configuring && timerStartUp.isActive()) timerStartUp.start(100); }); timerStartUp.start(); } connect(view->containment(), &Plasma::Containment::userConfiguringChanged , this, [&](bool configuring) { if (!configuring) saveConfig(); }); } void VisibilityManagerPrivate::setContainsMouse(bool contains) { if (containsMouse == contains) { return; } containsMouse = contains; emit q->containsMouseChanged(); - if (contains && mode != Dock::AlwaysVisible) { + if (contains && mode != Types::AlwaysVisible) { raiseView(true); } } void VisibilityManagerPrivate::viewEventManager(QEvent *ev) { switch (ev->type()) { case QEvent::Enter: setContainsMouse(true); break; case QEvent::Leave: setContainsMouse(false); updateHiddenState(); break; case QEvent::DragEnter: dragEnter = true; if (isHidden) emit q->mustBeShown(VisibilityManager::QPrivateSignal{}); break; case QEvent::DragLeave: case QEvent::Drop: dragEnter = false; updateHiddenState(); break; case QEvent::Show: wm->setViewExtraFlags(*view); break; default: break; } } void VisibilityManagerPrivate::cleanupFaultyWindows() { foreach (auto key, windows.keys()) { auto winfo = windows[key]; //! garbage windows removing if (winfo.geometry() == QRect(0, 0, 0, 0)) { //qDebug() << "Faulty Geometry ::: " << winfo.wid(); windows.remove(key); } } } //! Dynamic Background functions void VisibilityManagerPrivate::setEnabledDynamicBackground(bool active) { if (enabledDynamicBackgroundFlag == active) { return; } enabledDynamicBackgroundFlag = active; if (active) { - if (mode != Dock::DodgeAllWindows) { + if (mode != Types::DodgeAllWindows) { for (const auto &wid : wm->windows()) { windows.insert(wid, wm->requestInfo(wid)); } } connectionsDynBackground[0] = connect(view->corona(), &Plasma::Corona::availableScreenRectChanged, this, &VisibilityManagerPrivate::updateAvailableScreenGeometry); connectionsDynBackground[1] = connect(wm, &WindowSystem::windowChanged, this, [&](WindowId wid) { windows[wid] = wm->requestInfo(wid); updateDynamicBackgroundWindowFlags(); }); connectionsDynBackground[2] = connect(wm, &WindowSystem::windowRemoved, this, [&](WindowId wid) { windows.remove(wid); }); connectionsDynBackground[3] = connect(wm, &WindowSystem::windowAdded, this, [&](WindowId wid) { windows.insert(wid, wm->requestInfo(wid)); updateDynamicBackgroundWindowFlags(); }); connectionsDynBackground[4] = connect(wm, &WindowSystem::activeWindowChanged, this, [&](WindowId wid) { if (windows.contains(lastActiveWindowWid)) { windows[lastActiveWindowWid] = wm->requestInfo(lastActiveWindowWid); } windows[wid] = wm->requestInfo(wid); lastActiveWindowWid = wid; updateDynamicBackgroundWindowFlags(); }); connectionsDynBackground[5] = connect(wm, &WindowSystem::currentDesktopChanged, this, [&] { updateDynamicBackgroundWindowFlags(); }); connectionsDynBackground[6] = connect(wm, &WindowSystem::currentActivityChanged, this, [&] { updateDynamicBackgroundWindowFlags(); }); updateAvailableScreenGeometry(); updateDynamicBackgroundWindowFlags(); } else { // clear mode for (auto &c : connectionsDynBackground) { disconnect(c); } - if (mode != Dock::DodgeAllWindows) { + if (mode != Types::DodgeAllWindows) { windows.clear(); } // ATTENTION: this was creating a crash under wayland environment through the blur effect // setExistsWindowMaximized(false); // setExistsWindowSnapped(false); } emit q->enabledDynamicBackgroundChanged(); } void VisibilityManagerPrivate::setExistsWindowMaximized(bool windowMaximized) { if (windowIsMaximizedFlag == windowMaximized) { return; } windowIsMaximizedFlag = windowMaximized; emit q->existsWindowMaximizedChanged(); } void VisibilityManagerPrivate::setExistsWindowSnapped(bool windowSnapped) { if (windowIsSnappedFlag == windowSnapped) { return; } windowIsSnappedFlag = windowSnapped; emit q->existsWindowSnappedChanged(); } void VisibilityManagerPrivate::setTouchingWindowScheme(SchemeColors *scheme) { if (touchingScheme == scheme) { return; } touchingScheme = scheme; emit q->touchingWindowSchemeChanged(); } void VisibilityManagerPrivate::updateAvailableScreenGeometry() { if (!view || !view->containment()) { return; } int currentScrId = m_latteView->positioner()->currentScreenId(); - QRect tempAvailableScreenGeometry = m_corona->availableScreenRectWithCriteria(currentScrId, {Dock::AlwaysVisible}, {}); + QRect tempAvailableScreenGeometry = m_corona->availableScreenRectWithCriteria(currentScrId, {Types::AlwaysVisible}, {}); if (tempAvailableScreenGeometry != availableScreenGeometry) { availableScreenGeometry = tempAvailableScreenGeometry; snappedWindowsGeometries.clear(); //! for top view the snapped geometries would be int halfWidth1 = std::floor(availableScreenGeometry.width() / 2); int halfWidth2 = availableScreenGeometry.width() - halfWidth1; int halfHeight1 = std::floor((availableScreenGeometry.height()) / 2); int halfHeight2 = availableScreenGeometry.height() - halfHeight1; int x1 = availableScreenGeometry.x(); int x2 = availableScreenGeometry.x() + halfWidth1; int y1 = availableScreenGeometry.y(); int y2 = availableScreenGeometry.y() + halfHeight1; QRect snap1; QRect snap2; QRect snap3; QRect snap4; if (view->formFactor() == Plasma::Types::Horizontal) { if (view->location() == Plasma::Types::TopEdge) { snap1 = QRect(x1, y1, halfWidth1, halfHeight1); snap3 = QRect(x2, y1, halfWidth2, halfHeight1); } else if ((view->location() == Plasma::Types::BottomEdge)) { snap1 = QRect(x1, y2, halfWidth1, halfHeight2); snap3 = QRect(x2, y2, halfWidth2, halfHeight2); } snap2 = QRect(x1, y1, halfWidth1, availableScreenGeometry.height()); snap4 = QRect(x2, y1, halfWidth2, availableScreenGeometry.height()); } else if (view->formFactor() == Plasma::Types::Vertical) { QRect snap5; if (view->location() == Plasma::Types::LeftEdge) { snap1 = QRect(x1, y1, halfWidth1, halfHeight1); snap3 = QRect(x1, y2, halfWidth1, halfHeight2); snap5 = QRect(x1, y1, halfWidth1, availableScreenGeometry.height()); } else if ((view->location() == Plasma::Types::RightEdge)) { snap1 = QRect(x2, y1, halfWidth2, halfHeight1); snap3 = QRect(x2, y2, halfWidth2, halfHeight2); snap5 = QRect(x2, y1, halfWidth2, availableScreenGeometry.height()); } snap2 = QRect(x1, y1, availableScreenGeometry.width(), halfHeight1); snap4 = QRect(x1, y2, availableScreenGeometry.width(), halfHeight2); snappedWindowsGeometries.append(snap5); } snappedWindowsGeometries.append(snap1); snappedWindowsGeometries.append(snap2); snappedWindowsGeometries.append(snap3); snappedWindowsGeometries.append(snap4); updateDynamicBackgroundWindowFlags(); } } bool VisibilityManagerPrivate::isMaximizedInCurrentScreen(const WindowInfoWrap &winfo) { //! updated implementation to identify the screen that the maximized window is present //! in order to avoid: https://bugs.kde.org/show_bug.cgi?id=397700 if (winfo.isValid() && !winfo.isMinimized() && wm->isOnCurrentDesktop(winfo.wid()) && wm->isOnCurrentActivity(winfo.wid())) { if (winfo.isMaximized() && availableScreenGeometry.contains(winfo.geometry().center())) { return true; } } return false; } bool VisibilityManagerPrivate::isTouchingPanelEdge(const WindowInfoWrap &winfo) { if (winfo.isValid() && !winfo.isMinimized() && wm->isOnCurrentDesktop(winfo.wid()) && wm->isOnCurrentActivity(winfo.wid())) { bool touchingPanelEdge{false}; QRect screenGeometry = m_latteView->screenGeometry(); bool inCurrentScreen{screenGeometry.contains(winfo.geometry().topLeft()) || screenGeometry.contains(winfo.geometry().bottomRight())}; if (inCurrentScreen) { if (view->location() == Plasma::Types::TopEdge) { touchingPanelEdge = (winfo.geometry().y() == availableScreenGeometry.y()); } else if (view->location() == Plasma::Types::BottomEdge) { touchingPanelEdge = (winfo.geometry().bottom() == availableScreenGeometry.bottom()); } else if (view->location() == Plasma::Types::LeftEdge) { touchingPanelEdge = (winfo.geometry().x() == availableScreenGeometry.x()); } else if (view->location() == Plasma::Types::RightEdge) { touchingPanelEdge = (winfo.geometry().right() == availableScreenGeometry.right()); } } return touchingPanelEdge; } return false; } void VisibilityManagerPrivate::updateDynamicBackgroundWindowFlags() { bool foundSnap{false}; bool foundMaximized{false}; //! the notification window is not sending a remove signal and creates windows of geometry (0x0 0,0), //! maybe a garbage collector here is a good idea!!! bool existsFaultyWindow{false}; WindowId maxWinId; WindowId snapWinId; for (const auto &winfo : windows) { if (isMaximizedInCurrentScreen(winfo)) { foundMaximized = true; maxWinId = winfo.wid(); } if (winfo.isActive() && isTouchingPanelEdge(winfo)) { foundSnap = true; snapWinId = winfo.wid(); } if (!existsFaultyWindow && winfo.geometry() == QRect(0, 0, 0, 0)) { existsFaultyWindow = true; } //qDebug() << "window geometry ::: " << winfo.geometry(); } //! active windows that are touching the panel edge should have a higher priority //! this is why are identified first if (!foundSnap) { for (const auto &winfo : windows) { if ((winfo.isKeepAbove() && isTouchingPanelEdge(winfo)) || (!winfo.isActive() && snappedWindowsGeometries.contains(winfo.geometry()))) { foundSnap = true; snapWinId = winfo.wid(); break; } } } if (existsFaultyWindow) { cleanupFaultyWindows(); } /*if (!foundMaximized && !foundSnap) { qDebug() << "SCREEN GEOMETRY : " << availableScreenGeometry; qDebug() << "SNAPS ::: " << snappedWindowsGeometries; } qDebug() << " FOUND ::: " << foundMaximized << foundSnap;*/ setExistsWindowMaximized(foundMaximized); setExistsWindowSnapped(foundSnap); //! update color scheme for touching window if (foundSnap) { //! first the snap one because that would mean it is active setTouchingWindowScheme(wm->schemeForWindow(snapWinId)); } else if (foundMaximized) { setTouchingWindowScheme(wm->schemeForWindow(maxWinId)); } else { setTouchingWindowScheme(nullptr); } } //! KWin Edges Support functions void VisibilityManagerPrivate::setEnableKWinEdges(bool enable) { if (enableKWinEdgesFromUser == enable) { return; } enableKWinEdgesFromUser = enable; emit q->enableKWinEdgesChanged(); updateKWinEdgesSupport(); } void VisibilityManagerPrivate::updateKWinEdgesSupport() { - if (mode == Dock::AutoHide - || mode == Dock::DodgeActive - || mode == Dock::DodgeAllWindows - || mode == Dock::DodgeMaximized) { + if (mode == Types::AutoHide + || mode == Types::DodgeActive + || mode == Types::DodgeAllWindows + || mode == Types::DodgeMaximized) { if (enableKWinEdgesFromUser) { createEdgeGhostWindow(); } else if (!enableKWinEdgesFromUser) { deleteEdgeGhostWindow(); } - } else if (mode == Dock::AlwaysVisible - || mode == Dock::WindowsGoBelow) { + } else if (mode == Types::AlwaysVisible + || mode == Types::WindowsGoBelow) { deleteEdgeGhostWindow(); } } void VisibilityManagerPrivate::createEdgeGhostWindow() { if (!edgeGhostWindow) { edgeGhostWindow = new ScreenEdgeGhostWindow(m_latteView); wm->setViewExtraFlags(*edgeGhostWindow); connect(edgeGhostWindow, &ScreenEdgeGhostWindow::containsMouseChanged, this, [ = ](bool contains) { if (contains) { emit this->q->mustBeShown(VisibilityManager::QPrivateSignal{}); } }); connectionsKWinEdges[0] = connect(wm, &WindowSystem::currentActivityChanged, this, [&]() { - bool inCurrentLayout = (m_corona->layoutManager()->memoryUsage() == Dock::SingleLayout || - (m_corona->layoutManager()->memoryUsage() == Dock::MultipleLayouts + bool inCurrentLayout = (m_corona->layoutManager()->memoryUsage() == Types::SingleLayout || + (m_corona->layoutManager()->memoryUsage() == Types::MultipleLayouts && m_latteView->managedLayout() && !m_latteView->positioner()->inLocationChangeAnimation() && m_latteView->managedLayout()->name() == m_corona->layoutManager()->currentLayoutName())); if (edgeGhostWindow) { if (inCurrentLayout) { wm->setEdgeStateFor(edgeGhostWindow, isHidden); } else { wm->setEdgeStateFor(edgeGhostWindow, false); } } }); emit q->supportsKWinEdgesChanged(); } } void VisibilityManagerPrivate::deleteEdgeGhostWindow() { if (edgeGhostWindow) { edgeGhostWindow->deleteLater(); edgeGhostWindow = nullptr; for (auto &c : connectionsKWinEdges) { disconnect(c); } emit q->supportsKWinEdgesChanged(); } } //! Window Functions void VisibilityManagerPrivate::requestToggleMaximizeForActiveWindow() { WindowInfoWrap actInfo = wm->requestInfoActive(); //active window can be toggled only when it is in the same screen if (actInfo.isValid() && !actInfo.geometry().isNull() && m_latteView->screenGeometry().contains(actInfo.geometry().center())) { wm->requestToggleMaximized(actInfo.wid()); } } void VisibilityManagerPrivate::requestMoveActiveWindow(int localX, int localY) { WindowInfoWrap actInfo = wm->requestInfoActive(); //active window can be dragged only when it is in the same screen if (actInfo.isValid() && !actInfo.geometry().isNull() && m_latteView->screenGeometry().contains(actInfo.geometry().center())) { QPoint globalPoint{m_latteView->x() + localX, m_latteView->y() + localY}; wm->requestMoveWindow(actInfo.wid(), globalPoint); } } bool VisibilityManagerPrivate::activeWindowCanBeDragged() { WindowInfoWrap actInfo = wm->requestInfoActive(); //active window can be dragged only when it is in the same screen if (actInfo.isValid() && !actInfo.geometry().isNull() && m_latteView->screenGeometry().contains(actInfo.geometry().center())) { return wm->windowCanBeDragged(actInfo.wid()); } return false; } //! END: VisibilityManagerPrivate implementation //! BEGIN: VisibilityManager implementation VisibilityManager::VisibilityManager(PlasmaQuick::ContainmentView *view) : d(new VisibilityManagerPrivate(view, this)) { Latte::View *m_latteView = qobject_cast(view); if (m_latteView) { connect(this, &VisibilityManager::modeChanged, m_latteView->corona(), &Plasma::Corona::availableScreenRectChanged); } } VisibilityManager::~VisibilityManager() { qDebug() << "VisibilityManager deleting..."; delete d; } -Dock::Visibility VisibilityManager::mode() const +Types::Visibility VisibilityManager::mode() const { return d->mode; } -void VisibilityManager::setMode(Dock::Visibility mode) +void VisibilityManager::setMode(Types::Visibility mode) { d->setMode(mode); } void VisibilityManager::setWindowOnActivities(QWindow &window, const QStringList &activities) { d->setWindowOnActivities(window, activities); } void VisibilityManager::applyActivitiesToHiddenWindows(const QStringList &activities) { d->applyActivitiesToHiddenWindows(activities); } bool VisibilityManager::raiseOnDesktop() const { return d->raiseOnDesktopChange; } void VisibilityManager::setRaiseOnDesktop(bool enable) { d->setRaiseOnDesktop(enable); } bool VisibilityManager::raiseOnActivity() const { return d->raiseOnActivityChange; } void VisibilityManager::setRaiseOnActivity(bool enable) { d->setRaiseOnActivity(enable); } bool VisibilityManager::isHidden() const { return d->isHidden; } void VisibilityManager::setIsHidden(bool isHidden) { d->setIsHidden(isHidden); } bool VisibilityManager::blockHiding() const { return d->blockHiding; } void VisibilityManager::setBlockHiding(bool blockHiding) { d->setBlockHiding(blockHiding); } bool VisibilityManager::containsMouse() const { return d->containsMouse; } int VisibilityManager::timerShow() const { return d->timerShow.interval(); } void VisibilityManager::setTimerShow(int msec) { d->setTimerShow(msec); } int VisibilityManager::timerHide() const { return d->timerHide.interval(); } void VisibilityManager::setTimerHide(int msec) { d->setTimerHide(msec); } //! Dynamic Background functions bool VisibilityManager::enabledDynamicBackground() const { return d->enabledDynamicBackgroundFlag; } void VisibilityManager::setEnabledDynamicBackground(bool active) { d->setEnabledDynamicBackground(active); } bool VisibilityManager::existsWindowMaximized() const { return d->windowIsMaximizedFlag; } bool VisibilityManager::existsWindowSnapped() const { return d->windowIsSnappedFlag; } SchemeColors *VisibilityManager::touchingWindowScheme() const { return d->touchingScheme; } //! KWin Edges Support functions bool VisibilityManager::enableKWinEdges() const { return d->enableKWinEdgesFromUser; } void VisibilityManager::setEnableKWinEdges(bool enable) { d->setEnableKWinEdges(enable); } bool VisibilityManager::supportsKWinEdges() const { return (d->edgeGhostWindow != nullptr); } //! Window Functions void VisibilityManager::requestToggleMaximizeForActiveWindow() { d->requestToggleMaximizeForActiveWindow(); } void VisibilityManager::requestMoveActiveWindow(int localX, int localY) { d->requestMoveActiveWindow(localX, localY); } bool VisibilityManager::activeWindowCanBeDragged() { return d->activeWindowCanBeDragged(); } //! END: VisibilityManager implementation } diff --git a/app/view/visibilitymanager.h b/app/view/visibilitymanager.h index 270a4b77..8c18597c 100644 --- a/app/view/visibilitymanager.h +++ b/app/view/visibilitymanager.h @@ -1,145 +1,145 @@ /* * 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 . */ #ifndef VISIBILITYMANAGER_H #define VISIBILITYMANAGER_H // local #include "../plasmaquick/containmentview.h" #include "../schemecolors.h" #include "../wm/windowinfowrap.h" -#include "../../liblattedock/dock.h" +#include "../../liblatte2/types.h" // Qt #include #include // Plasma #include namespace Latte { class VisibilityManagerPrivate; class VisibilityManager : public QObject { Q_OBJECT - Q_PROPERTY(Latte::Dock::Visibility mode READ mode WRITE setMode NOTIFY modeChanged) + Q_PROPERTY(Latte::Types::Visibility mode READ mode WRITE setMode NOTIFY modeChanged) Q_PROPERTY(bool raiseOnDesktop READ raiseOnDesktop WRITE setRaiseOnDesktop NOTIFY raiseOnDesktopChanged) Q_PROPERTY(bool raiseOnActivity READ raiseOnActivity WRITE setRaiseOnActivity NOTIFY raiseOnActivityChanged) Q_PROPERTY(bool isHidden READ isHidden WRITE setIsHidden NOTIFY isHiddenChanged) Q_PROPERTY(bool blockHiding READ blockHiding WRITE setBlockHiding NOTIFY blockHidingChanged) Q_PROPERTY(bool containsMouse READ containsMouse NOTIFY containsMouseChanged) //! Dynamic Background Feature (needed options) Q_PROPERTY(bool enabledDynamicBackground READ enabledDynamicBackground WRITE setEnabledDynamicBackground NOTIFY enabledDynamicBackgroundChanged) Q_PROPERTY(bool existsWindowMaximized READ existsWindowMaximized NOTIFY existsWindowMaximizedChanged) Q_PROPERTY(bool existsWindowSnapped READ existsWindowSnapped NOTIFY existsWindowSnappedChanged) Q_PROPERTY(SchemeColors *touchingWindowScheme READ touchingWindowScheme NOTIFY touchingWindowSchemeChanged) //! KWin Edges Support Options Q_PROPERTY(bool enableKWinEdges READ enableKWinEdges WRITE setEnableKWinEdges NOTIFY enableKWinEdgesChanged) Q_PROPERTY(bool supportsKWinEdges READ supportsKWinEdges NOTIFY supportsKWinEdgesChanged) Q_PROPERTY(int timerShow READ timerShow WRITE setTimerShow NOTIFY timerShowChanged) Q_PROPERTY(int timerHide READ timerHide WRITE setTimerHide NOTIFY timerHideChanged) public: explicit VisibilityManager(PlasmaQuick::ContainmentView *view); virtual ~VisibilityManager(); - Latte::Dock::Visibility mode() const; - void setMode(Latte::Dock::Visibility mode); + Latte::Types::Visibility mode() const; + void setMode(Latte::Types::Visibility mode); void setWindowOnActivities(QWindow &window, const QStringList &activities); void applyActivitiesToHiddenWindows(const QStringList &activities); bool raiseOnDesktop() const; void setRaiseOnDesktop(bool enable); bool raiseOnActivity() const; void setRaiseOnActivity(bool enable); bool isHidden() const; void setIsHidden(bool isHidden); bool blockHiding() const; void setBlockHiding(bool blockHiding); bool containsMouse() const; int timerShow() const; void setTimerShow(int msec); int timerHide() const; void setTimerHide(int msec); //! Dynamic Background functions bool enabledDynamicBackground() const; void setEnabledDynamicBackground(bool active); bool existsWindowMaximized() const; bool existsWindowSnapped() const; SchemeColors *touchingWindowScheme() const; //! KWin Edges Support functions bool enableKWinEdges() const; void setEnableKWinEdges(bool enable); bool supportsKWinEdges() const; public slots: Q_INVOKABLE void requestToggleMaximizeForActiveWindow(); Q_INVOKABLE void requestMoveActiveWindow(int localX, int localY); Q_INVOKABLE bool activeWindowCanBeDragged(); signals: void mustBeShown(QPrivateSignal); void mustBeHide(QPrivateSignal); void modeChanged(); void raiseOnDesktopChanged(); void raiseOnActivityChanged(); void isHiddenChanged(); void blockHidingChanged(); void containsMouseChanged(); void timerShowChanged(); void timerHideChanged(); void touchingWindowSchemeChanged(); //! Dynamic Background signals (from options) void enabledDynamicBackgroundChanged(); void existsWindowMaximizedChanged(); void existsWindowSnappedChanged(); //! KWin Edges Support signals void enableKWinEdgesChanged(); void supportsKWinEdgesChanged(); private: VisibilityManagerPrivate *const d; friend class VisibilityManagerPrivate; }; } #endif // VISIBILITYMANAGER_H diff --git a/app/view/visibilitymanager_p.h b/app/view/visibilitymanager_p.h index eadbbb81..3f32af8d 100644 --- a/app/view/visibilitymanager_p.h +++ b/app/view/visibilitymanager_p.h @@ -1,142 +1,142 @@ #ifndef VISIBILITYMANAGERPRIVATE_H #define VISIBILITYMANAGERPRIVATE_H // local #include "../schemecolors.h" #include "../wm/abstractwindowinterface.h" #include "../wm/windowinfowrap.h" -#include "../../liblattedock/dock.h" +#include "../../liblatte2/types.h" // C++ #include #include // Qt #include #include #include #include #include // Plasma #include namespace Latte { class Corona; class View; class VisibilityManager; class ScreenEdgeGhostWindow; /*! * \brief The Latte::VisibilityManagerPrivate is a class d-pointer */ class VisibilityManagerPrivate : public QObject { Q_GADGET public: VisibilityManagerPrivate(PlasmaQuick::ContainmentView *view, VisibilityManager *q); ~VisibilityManagerPrivate(); - void setMode(Dock::Visibility mode); + void setMode(Types::Visibility mode); void setRaiseOnDesktop(bool enable); void setRaiseOnActivity(bool enable); void setContainsMouse(bool contains); void setIsHidden(bool isHidden); void setBlockHiding(bool blockHiding); void setTimerShow(int msec); void setTimerHide(int msec); void raiseView(bool raise); void raiseViewTemporarily(); void updateHiddenState(); //! the notification window is not sending a remove signal and creates windows of geometry (0x0 0,0), //! this is a garbage collector to collect such windows in order to not break the windows array validity. void cleanupFaultyWindows(); //! Dynamic Background Feature void setEnabledDynamicBackground(bool active); void setExistsWindowMaximized(bool windowMaximized); void setExistsWindowSnapped(bool windowSnapped); void setTouchingWindowScheme(SchemeColors *scheme); void updateAvailableScreenGeometry(); void updateDynamicBackgroundWindowFlags(); //! KWin Edges Support functions void createEdgeGhostWindow(); void deleteEdgeGhostWindow(); void setEnableKWinEdges(bool enable); void updateKWinEdgesSupport(); void setViewGeometry(const QRect &rect); void setWindowOnActivities(QWindow &window, const QStringList &activities); void applyActivitiesToHiddenWindows(const QStringList &activities); void windowAdded(WindowId id); void dodgeActive(WindowId id); void dodgeMaximized(WindowId id); void dodgeWindows(WindowId id); void checkAllWindows(); bool intersects(const WindowInfoWrap &winfo); bool isMaximizedInCurrentScreen(const WindowInfoWrap &winfo); bool isTouchingPanelEdge(const WindowInfoWrap &winfo); void updateStrutsBasedOnLayoutsAndActivities(); void requestToggleMaximizeForActiveWindow(); void requestMoveActiveWindow(int localX, int localY); bool activeWindowCanBeDragged(); void saveConfig(); void restoreConfig(); void viewEventManager(QEvent *ev); VisibilityManager *q; PlasmaQuick::ContainmentView *view; AbstractWindowInterface *wm; - Dock::Visibility mode{Dock::None}; + Types::Visibility mode{Types::None}; std::array connections; QMap windows; QTimer timerShow; QTimer timerHide; QTimer timerCheckWindows; QTimer timerStartUp; QRect m_viewGeometry; bool isHidden{false}; bool dragEnter{false}; bool blockHiding{false}; bool containsMouse{false}; bool raiseTemporarily{false}; bool raiseOnDesktopChange{false}; bool raiseOnActivityChange{false}; bool hideNow{false}; //! Dynamic Background flags and needed information bool enabledDynamicBackgroundFlag{false}; bool windowIsSnappedFlag{false}; bool windowIsMaximizedFlag{false}; QRect availableScreenGeometry; QList snappedWindowsGeometries; std::array connectionsDynBackground; WindowId lastActiveWindowWid; SchemeColors *touchingScheme{nullptr}; //! KWin Edges bool enableKWinEdgesFromUser{true}; std::array connectionsKWinEdges; ScreenEdgeGhostWindow *edgeGhostWindow{nullptr}; Latte::Corona *m_corona{nullptr}; Latte::View *m_latteView{nullptr}; }; } #endif // VISIBILITYMANAGERPRIVATE_H diff --git a/app/wm/abstractwindowinterface.h b/app/wm/abstractwindowinterface.h index 0f3179b3..f01a7224 100644 --- a/app/wm/abstractwindowinterface.h +++ b/app/wm/abstractwindowinterface.h @@ -1,131 +1,131 @@ /* * 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 . */ #ifndef ABSTRACTWINDOWINTERFACE_H #define ABSTRACTWINDOWINTERFACE_H // local #include "schemecolors.h" #include "windowinfowrap.h" -#include "../liblattedock/dock.h" -#include "../liblattedock/extras.h" +#include "../liblatte2/types.h" +#include "../liblatte2/extras.h" // C++ #include #include // Qt #include #include #include #include #include #include #include #include // KDE #include // Plasma #include namespace Latte { class XWindowInterface; class WaylandInterface; class AbstractWindowInterface : public QObject { Q_OBJECT public: enum class Slide { None, Top, Left, Bottom, Right, }; explicit AbstractWindowInterface(QObject *parent = nullptr); virtual ~AbstractWindowInterface(); virtual void setViewExtraFlags(QWindow &view) = 0; virtual void setViewStruts(QWindow &view, const QRect &rect , Plasma::Types::Location location) = 0; virtual void setWindowOnActivities(QWindow &window, const QStringList &activities) = 0; virtual void removeViewStruts(QWindow &view) const = 0; virtual WindowId activeWindow() const = 0; virtual WindowInfoWrap requestInfo(WindowId wid) const = 0; virtual WindowInfoWrap requestInfoActive() const = 0; virtual bool isOnCurrentDesktop(WindowId wid) const = 0; virtual bool isOnCurrentActivity(WindowId wid) const = 0; virtual const std::list &windows() const = 0; virtual void setKeepAbove(const QDialog &dialog, bool above = true) const = 0; virtual void skipTaskBar(const QDialog &dialog) const = 0; virtual void slideWindow(QWindow &view, Slide location) const = 0; virtual void enableBlurBehind(QWindow &view) const = 0; virtual void setEdgeStateFor(QWindow *view, bool active) const = 0; virtual void requestToggleMaximized(WindowId wid) const = 0; virtual void requestMoveWindow(WindowId wid, QPoint from) const = 0; virtual bool windowCanBeDragged(WindowId wid) const = 0; void addView(WindowId wid); void removeView(WindowId wid); SchemeColors *schemeForWindow(WindowId wId); void setColorSchemeForWindow(WindowId wId, QString scheme); signals: void activeWindowChanged(WindowId wid); void windowChanged(WindowId winfo); void windowAdded(WindowId wid); void windowRemoved(WindowId wid); void currentDesktopChanged(); void currentActivityChanged(); protected: std::list m_windows; std::list m_views; QPointer m_activities; private slots: void updateDefaultScheme(); private: //! scheme file and its loaded colors QMap m_schemes; //! window id and its corresponding scheme file QMap m_windowScheme; }; // namespace alias using WindowSystem = AbstractWindowInterface; } #endif // ABSTRACTWINDOWINTERFACE_H diff --git a/app/wm/waylandinterface.cpp b/app/wm/waylandinterface.cpp index 8daa58d5..5549c914 100644 --- a/app/wm/waylandinterface.cpp +++ b/app/wm/waylandinterface.cpp @@ -1,440 +1,440 @@ /* * 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 "waylandinterface.h" // local #include "view/screenedgeghostwindow.h" #include "view/view.h" #include "../lattecorona.h" -#include "../liblattedock/extras.h" +#include "../liblatte2/extras.h" // Qt #include #include #include #include #include #include // KDE #include #include #include // X11 #include using namespace KWayland::Client; namespace Latte { class Private::GhostWindow : public QRasterWindow { Q_OBJECT public: GhostWindow(WaylandInterface *waylandInterface) : m_waylandInterface(waylandInterface) { setFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::NoDropShadowWindowHint | Qt::WindowDoesNotAcceptFocus); setupWaylandIntegration(); show(); } ~GhostWindow() { delete m_shellSurface; } void setGeometry(const QRect &rect) { QWindow::setGeometry(rect); setMaximumSize(rect.size()); m_shellSurface->setPosition(rect.topLeft()); } void setupWaylandIntegration() { using namespace KWayland::Client; if (m_shellSurface) return; Surface *s{Surface::fromWindow(this)}; if (!s) return; m_shellSurface = m_waylandInterface->waylandCoronaInterface()->createSurface(s, this); qDebug() << "wayland ghost window surface was created..."; m_shellSurface->setSkipTaskbar(true); m_shellSurface->setPanelTakesFocus(false); m_shellSurface->setRole(PlasmaShellSurface::Role::Panel); m_shellSurface->setPanelBehavior(PlasmaShellSurface::PanelBehavior::AlwaysVisible); } KWayland::Client::PlasmaShellSurface *m_shellSurface{nullptr}; WaylandInterface *m_waylandInterface{nullptr}; }; WaylandInterface::WaylandInterface(QObject *parent) : AbstractWindowInterface(parent) { m_corona = qobject_cast(parent); m_activities = new KActivities::Consumer(this); connect(m_activities.data(), &KActivities::Consumer::currentActivityChanged , this, &WaylandInterface::currentActivityChanged); } WaylandInterface::~WaylandInterface() { } void WaylandInterface::init() { } void WaylandInterface::initWindowManagement(KWayland::Client::PlasmaWindowManagement *windowManagement) { m_windowManagement = windowManagement; connect(m_windowManagement, &PlasmaWindowManagement::windowCreated, this, &WaylandInterface::windowCreatedProxy); connect(m_windowManagement, &PlasmaWindowManagement::activeWindowChanged, this, [&]() noexcept { auto w = m_windowManagement->activeWindow(); emit activeWindowChanged(w ? w->internalId() : 0); }, Qt::QueuedConnection); } KWayland::Client::PlasmaShell *WaylandInterface::waylandCoronaInterface() const { return m_corona->waylandCoronaInterface(); } void WaylandInterface::setViewExtraFlags(QWindow &view) { Q_UNUSED(view) } void WaylandInterface::setViewStruts(QWindow &view, const QRect &rect, Plasma::Types::Location location) { if (!m_ghostWindows.contains(view.winId())) m_ghostWindows[view.winId()] = new Private::GhostWindow(this); auto w = m_ghostWindows[view.winId()]; switch (location) { case Plasma::Types::TopEdge: case Plasma::Types::BottomEdge: w->setGeometry({rect.x() + rect.width() / 2, rect.y(), 1, rect.height()}); break; case Plasma::Types::LeftEdge: case Plasma::Types::RightEdge: w->setGeometry({rect.x(), rect.y() + rect.height() / 2, rect.width(), 1}); break; default: break; } } void WaylandInterface::setWindowOnActivities(QWindow &window, const QStringList &activities) { //! needs to updated to wayland case // KWindowSystem::setOnActivities(view.winId(), activities); } void WaylandInterface::removeViewStruts(QWindow &view) const { delete m_ghostWindows.take(view.winId()); } WindowId WaylandInterface::activeWindow() const { if (!m_windowManagement) { return 0; } auto wid = m_windowManagement->activeWindow(); return wid ? wid->internalId() : 0; } const std::list &WaylandInterface::windows() const { return m_windows; } void WaylandInterface::setKeepAbove(const QDialog &dialog, bool above) const { if (above) { KWindowSystem::setState(dialog.winId(), NET::KeepAbove); } else { KWindowSystem::clearState(dialog.winId(), NET::KeepAbove); } } void WaylandInterface::skipTaskBar(const QDialog &dialog) const { KWindowSystem::setState(dialog.winId(), NET::SkipTaskbar); } void WaylandInterface::slideWindow(QWindow &view, AbstractWindowInterface::Slide location) const { auto slideLocation = KWindowEffects::NoEdge; switch (location) { case Slide::Top: slideLocation = KWindowEffects::TopEdge; break; case Slide::Bottom: slideLocation = KWindowEffects::BottomEdge; break; case Slide::Left: slideLocation = KWindowEffects::LeftEdge; break; case Slide::Right: slideLocation = KWindowEffects::RightEdge; break; default: break; } KWindowEffects::slideWindow(view.winId(), slideLocation, -1); } void WaylandInterface::enableBlurBehind(QWindow &view) const { KWindowEffects::enableBlurBehind(view.winId()); } void WaylandInterface::setEdgeStateFor(QWindow *view, bool active) const { ScreenEdgeGhostWindow *window = qobject_cast(view); if (!window) { return; } if (window->parentView()->surface() && window->parentView()->visibility() - && (window->parentView()->visibility()->mode() == Dock::DodgeActive - || window->parentView()->visibility()->mode() == Dock::DodgeMaximized - || window->parentView()->visibility()->mode() == Dock::DodgeAllWindows - || window->parentView()->visibility()->mode() == Dock::AutoHide)) { + && (window->parentView()->visibility()->mode() == Types::DodgeActive + || window->parentView()->visibility()->mode() == Types::DodgeMaximized + || window->parentView()->visibility()->mode() == Types::DodgeAllWindows + || window->parentView()->visibility()->mode() == Types::AutoHide)) { if (active) { window->showWithMask(); window->surface()->requestHideAutoHidingPanel(); } else { window->hideWithMask(); window->surface()->requestShowAutoHidingPanel(); } } } WindowInfoWrap WaylandInterface::requestInfoActive() const { if (!m_windowManagement) { return {}; } auto w = m_windowManagement->activeWindow(); if (!w) return {}; WindowInfoWrap winfoWrap; winfoWrap.setIsValid(true); winfoWrap.setWid(w->internalId()); winfoWrap.setIsActive(w->isActive()); winfoWrap.setIsMinimized(w->isMinimized()); winfoWrap.setIsMaxVert(w->isMaximized()); winfoWrap.setIsMaxHoriz(w->isMaximized()); winfoWrap.setIsFullscreen(w->isFullscreen()); winfoWrap.setIsShaded(w->isShaded()); winfoWrap.setGeometry(w->geometry()); winfoWrap.setIsKeepAbove(w->isKeepAbove()); winfoWrap.setHasSkipTaskbar(w->skipTaskbar()); return winfoWrap; } bool WaylandInterface::isOnCurrentDesktop(WindowId wid) const { if (!m_windowManagement) { return false; } auto it = std::find_if(m_windowManagement->windows().constBegin(), m_windowManagement->windows().constEnd(), [&wid](PlasmaWindow * w) noexcept { return w->isValid() && w->internalId() == wid; }); //qDebug() << "desktop:" << (it != m_windowManagement->windows().constEnd() ? (*it)->virtualDesktop() : -1) << KWindowSystem::currentDesktop(); //return true; return it != m_windowManagement->windows().constEnd() && ((*it)->virtualDesktop() == KWindowSystem::currentDesktop() || (*it)->isOnAllDesktops()); } bool WaylandInterface::isOnCurrentActivity(WindowId wid) const { auto it = std::find_if(m_windowManagement->windows().constBegin(), m_windowManagement->windows().constEnd(), [&wid](PlasmaWindow * w) noexcept { return w->isValid() && w->internalId() == wid; }); //TODO: Not yet implemented return it != m_windowManagement->windows().constEnd() && true; } WindowInfoWrap WaylandInterface::requestInfo(WindowId wid) const { WindowInfoWrap winfoWrap; auto w = windowFor(wid); if (w) { if (isValidWindow(w)) { winfoWrap.setIsValid(true); winfoWrap.setWid(wid); winfoWrap.setIsActive(w->isActive()); winfoWrap.setIsMinimized(w->isMinimized()); winfoWrap.setIsMaxVert(w->isMaximized()); winfoWrap.setIsMaxHoriz(w->isMaximized()); winfoWrap.setIsFullscreen(w->isFullscreen()); winfoWrap.setIsShaded(w->isShaded()); winfoWrap.setGeometry(w->geometry()); winfoWrap.setHasSkipTaskbar(w->skipTaskbar()); } else if (w->appId() == QLatin1String("org.kde.plasmashell")) { winfoWrap.setIsValid(true); winfoWrap.setIsPlasmaDesktop(true); winfoWrap.setWid(wid); } } else { return {}; } return winfoWrap; } KWayland::Client::PlasmaWindow *WaylandInterface::windowFor(WindowId wid) const { auto it = std::find_if(m_windowManagement->windows().constBegin(), m_windowManagement->windows().constEnd(), [&wid](PlasmaWindow * w) noexcept { return w->isValid() && w->internalId() == wid; }); if (it == m_windowManagement->windows().constEnd()) { return nullptr; } return *it; } bool WaylandInterface::windowCanBeDragged(WindowId wid) const { WindowInfoWrap winfo = requestInfo(wid); return (winfo.isValid() && !winfo.isPlasmaDesktop() && !winfo.hasSkipTaskbar()); } void WaylandInterface::requestMoveWindow(WindowId wid, QPoint from) const { if (windowCanBeDragged(wid)) { auto w = windowFor(wid); if (w && isValidWindow(w)) { w->requestMove(); } } } void WaylandInterface::requestToggleMaximized(WindowId wid) const { auto w = windowFor(wid); if (w && isValidWindow(w)) { w->requestToggleMaximized(); } } inline bool WaylandInterface::isValidWindow(const KWayland::Client::PlasmaWindow *w) const { //! because wayland does not have any way yet to identify the window type //! a trick is to just consider windows as valid when they can be shown in the //! taskbar. Of course that creates issues with plasma native dialogs //! e.g. widgets explorer, Activities etc. that are not used to hide //! the dodge views appropriately return w->isValid() && !w->skipTaskbar(); } void WaylandInterface::windowCreatedProxy(KWayland::Client::PlasmaWindow *w) { if (!isValidWindow(w)) return; if (!mapper) mapper = new QSignalMapper(this); mapper->setMapping(w, w); connect(w, &PlasmaWindow::unmapped, this, [ &, win = w]() noexcept { mapper->removeMappings(win); m_windows.remove(win->internalId()); emit windowRemoved(win->internalId()); }); connect(w, SIGNAL(activeChanged()), mapper, SLOT(map())); connect(w, SIGNAL(fullscreenChanged()), mapper, SLOT(map())); connect(w, SIGNAL(geometryChanged()), mapper, SLOT(map())); connect(w, SIGNAL(maximizedChanged()), mapper, SLOT(map())); connect(w, SIGNAL(minimizedChanged()), mapper, SLOT(map())); connect(w, SIGNAL(shadedChanged()), mapper, SLOT(map())); connect(w, SIGNAL(skipTaskbarChanged()), mapper, SLOT(map())); connect(w, SIGNAL(onAllDesktopsChanged()), mapper, SLOT(map())); connect(w, SIGNAL(virtualDesktopChanged()), mapper, SLOT(map())); connect(mapper, static_cast(&QSignalMapper::mapped) , this, [&](QObject * w) noexcept { //qDebug() << "window changed:" << qobject_cast(w)->appId(); emit windowChanged(qobject_cast(w)->internalId()); }); m_windows.push_back(w->internalId()); emit windowAdded(w->internalId()); } } #include "waylandinterface.moc" diff --git a/app/wm/xwindowinterface.cpp b/app/wm/xwindowinterface.cpp index 5a6edc6b..4275396b 100644 --- a/app/wm/xwindowinterface.cpp +++ b/app/wm/xwindowinterface.cpp @@ -1,441 +1,441 @@ /* * 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 "xwindowinterface.h" // local #include "view/screenedgeghostwindow.h" #include "view/view.h" -#include "../liblattedock/extras.h" +#include "../liblatte2/extras.h" // Qt #include #include #include // KDE #include #include // X11 #include #include namespace Latte { XWindowInterface::XWindowInterface(QObject *parent) : AbstractWindowInterface(parent) { m_activities = new KActivities::Consumer(this); connect(KWindowSystem::self(), &KWindowSystem::activeWindowChanged , this, &AbstractWindowInterface::activeWindowChanged); connect(KWindowSystem::self() , static_cast (&KWindowSystem::windowChanged) , this, &XWindowInterface::windowChangedProxy); auto addWindow = [&](WindowId wid) { if (std::find(m_windows.cbegin(), m_windows.cend(), wid) == m_windows.cend()) { if (isValidWindow(KWindowInfo(wid.value(), NET::WMWindowType))) { m_windows.push_back(wid); emit windowAdded(wid); } } }; connect(KWindowSystem::self(), &KWindowSystem::windowAdded, this, addWindow); connect(KWindowSystem::self(), &KWindowSystem::windowRemoved, [this](WindowId wid) noexcept { if (std::find(m_windows.cbegin(), m_windows.cend(), wid) != m_windows.end()) { m_windows.remove(wid); emit windowRemoved(wid); } }); connect(KWindowSystem::self(), &KWindowSystem::currentDesktopChanged , this, &XWindowInterface::currentDesktopChanged); connect(m_activities.data(), &KActivities::Consumer::currentActivityChanged , this, &XWindowInterface::currentActivityChanged); // fill windows list foreach (const auto &wid, KWindowSystem::self()->windows()) { addWindow(wid); } } XWindowInterface::~XWindowInterface() { } void XWindowInterface::setViewExtraFlags(QWindow &view) { NETWinInfo winfo(QX11Info::connection() , static_cast(view.winId()) , static_cast(view.winId()) , 0, 0); winfo.setAllowedActions(NET::ActionChangeDesktop); KWindowSystem::setType(view.winId(), NET::Dock); KWindowSystem::setState(view.winId(), NET::SkipTaskbar | NET::SkipPager); KWindowSystem::setOnAllDesktops(view.winId(), true); } void XWindowInterface::setViewStruts(QWindow &view, const QRect &rect , Plasma::Types::Location location) { NETExtendedStrut strut; const auto screen = view.screen(); const QRect currentScreen {screen->geometry()}; const QRect wholeScreen {{0, 0}, screen->virtualSize()}; switch (location) { case Plasma::Types::TopEdge: { const int topOffset {screen->geometry().top()}; strut.top_width = rect.height() + topOffset; strut.top_start = rect.x(); strut.top_end = rect.x() + rect.width() - 1; break; } case Plasma::Types::BottomEdge: { const int bottomOffset {wholeScreen.bottom() - currentScreen.bottom()}; strut.bottom_width = rect.height() + bottomOffset; strut.bottom_start = rect.x(); strut.bottom_end = rect.x() + rect.width() - 1; break; } case Plasma::Types::LeftEdge: { const int leftOffset = {screen->geometry().left()}; strut.left_width = rect.width() + leftOffset; strut.left_start = rect.y(); strut.left_end = rect.y() + rect.height() - 1; break; } case Plasma::Types::RightEdge: { const int rightOffset = {wholeScreen.right() - currentScreen.right()}; strut.right_width = rect.width() + rightOffset; strut.right_start = rect.y(); strut.right_end = rect.y() + rect.height() - 1; break; } default: qWarning() << "wrong location:" << qEnumToStr(location); return; } KWindowSystem::setExtendedStrut(view.winId(), strut.left_width, strut.left_start, strut.left_end, strut.right_width, strut.right_start, strut.right_end, strut.top_width, strut.top_start, strut.top_end, strut.bottom_width, strut.bottom_start, strut.bottom_end ); } void XWindowInterface::setWindowOnActivities(QWindow &window, const QStringList &activities) { KWindowSystem::setOnActivities(window.winId(), activities); } void XWindowInterface::removeViewStruts(QWindow &view) const { KWindowSystem::setStrut(view.winId(), 0, 0, 0, 0); } WindowId XWindowInterface::activeWindow() const { return KWindowSystem::self()->activeWindow(); } const std::list &XWindowInterface::windows() const { return m_windows; } void XWindowInterface::setKeepAbove(const QDialog &dialog, bool above) const { if (above) { KWindowSystem::setState(dialog.winId(), NET::KeepAbove); } else { KWindowSystem::clearState(dialog.winId(), NET::KeepAbove); } } void XWindowInterface::skipTaskBar(const QDialog &dialog) const { KWindowSystem::setState(dialog.winId(), NET::SkipTaskbar); } void XWindowInterface::slideWindow(QWindow &view, AbstractWindowInterface::Slide location) const { auto slideLocation = KWindowEffects::NoEdge; switch (location) { case Slide::Top: slideLocation = KWindowEffects::TopEdge; break; case Slide::Bottom: slideLocation = KWindowEffects::BottomEdge; break; case Slide::Left: slideLocation = KWindowEffects::LeftEdge; break; case Slide::Right: slideLocation = KWindowEffects::RightEdge; break; default: break; } KWindowEffects::slideWindow(view.winId(), slideLocation, -1); } void XWindowInterface::enableBlurBehind(QWindow &view) const { KWindowEffects::enableBlurBehind(view.winId()); } void XWindowInterface::setEdgeStateFor(QWindow *view, bool active) const { ScreenEdgeGhostWindow *window = qobject_cast(view); if (!window) { return; } xcb_connection_t *c = QX11Info::connection(); const QByteArray effectName = QByteArrayLiteral("_KDE_NET_WM_SCREEN_EDGE_SHOW"); xcb_intern_atom_cookie_t atomCookie = xcb_intern_atom_unchecked(c, false, effectName.length(), effectName.constData()); QScopedPointer atom(xcb_intern_atom_reply(c, atomCookie, nullptr)); if (!atom) { return; } if (!active) { xcb_delete_property(c, window->winId(), atom->atom); window->hideWithMask(); return; } window->showWithMask(); uint32_t value = 0; switch (window->location()) { case Plasma::Types::TopEdge: value = 0; break; case Plasma::Types::RightEdge: value = 1; break; case Plasma::Types::BottomEdge: value = 2; break; case Plasma::Types::LeftEdge: value = 3; break; case Plasma::Types::Floating: default: value = 4; break; } int hideType = 0; value |= hideType << 8; xcb_change_property(c, XCB_PROP_MODE_REPLACE, window->winId(), atom->atom, XCB_ATOM_CARDINAL, 32, 1, &value); } WindowInfoWrap XWindowInterface::requestInfoActive() const { return requestInfo(KWindowSystem::activeWindow()); } bool XWindowInterface::isOnCurrentDesktop(WindowId wid) const { KWindowInfo winfo(wid.value(), NET::WMDesktop); return winfo.valid() && winfo.isOnCurrentDesktop(); } bool XWindowInterface::isOnCurrentActivity(WindowId wid) const { KWindowInfo winfo(wid.value(), 0, NET::WM2Activities); return winfo.valid() && (winfo.activities().contains(m_activities->currentActivity()) || winfo.activities().empty()); } WindowInfoWrap XWindowInterface::requestInfo(WindowId wid) const { const KWindowInfo winfo{wid.value(), NET::WMFrameExtents | NET::WMWindowType | NET::WMGeometry | NET::WMState}; WindowInfoWrap winfoWrap; if (isValidWindow(winfo)) { winfoWrap.setIsValid(true); winfoWrap.setWid(wid); winfoWrap.setIsActive(KWindowSystem::activeWindow() == wid.value()); winfoWrap.setIsMinimized(winfo.hasState(NET::Hidden)); winfoWrap.setIsMaxVert(winfo.hasState(NET::MaxVert)); winfoWrap.setIsMaxHoriz(winfo.hasState(NET::MaxHoriz)); winfoWrap.setIsFullscreen(winfo.hasState(NET::FullScreen)); winfoWrap.setIsShaded(winfo.hasState(NET::Shaded)); winfoWrap.setGeometry(winfo.frameGeometry()); winfoWrap.setIsKeepAbove(winfo.hasState(NET::KeepAbove)); winfoWrap.setHasSkipTaskbar(winfo.hasState(NET::SkipTaskbar)); } else if (m_desktopId == wid) { winfoWrap.setIsValid(true); winfoWrap.setIsPlasmaDesktop(true); winfoWrap.setWid(wid); winfoWrap.setHasSkipTaskbar(true); } return winfoWrap; } bool XWindowInterface::windowCanBeDragged(WindowId wid) const { WindowInfoWrap winfo = requestInfo(wid); return (winfo.isValid() && !winfo.isPlasmaDesktop() && !winfo.hasSkipTaskbar()); } void XWindowInterface::requestMoveWindow(WindowId wid, QPoint from) const { WindowInfoWrap wInfo = requestInfo(wid); if (!wInfo.isValid() || wInfo.isPlasmaDesktop()) { return; } int borderX{wInfo.geometry().width() > 120 ? 60 : 10}; int borderY{10}; //! find min/max values for x,y based on active window geometry int minX = wInfo.geometry().x() + borderX; int maxX = wInfo.geometry().x() + wInfo.geometry().width() - borderX; int minY = wInfo.geometry().y() + borderY; int maxY = wInfo.geometry().y() + wInfo.geometry().height() - borderY; //! set the point from which this window will be moved, //! make sure that it is in window boundaries int validX = qBound(minX, from.x(), maxX); int validY = qBound(minY, from.y(), maxY); NETRootInfo ri(QX11Info::connection(), NET::WMMoveResize); ri.moveResizeRequest(wInfo.wid().toUInt(), validX, validY, NET::Move); } void XWindowInterface::requestToggleMaximized(WindowId wid) const { WindowInfoWrap wInfo = requestInfo(wid); bool restore = wInfo.isMaxHoriz() && wInfo.isMaxVert(); NETWinInfo ni(QX11Info::connection(), wid.toInt(), QX11Info::appRootWindow(), NET::WMState, NET::Properties2()); if (restore) { ni.setState(NET::States(), NET::Max); } else { ni.setState(NET::Max, NET::Max); } } bool XWindowInterface::isValidWindow(const KWindowInfo &winfo) const { constexpr auto types = NET::DockMask | NET::MenuMask | NET::SplashMask | NET::NormalMask; auto winType = winfo.windowType(types); if (winType == -1) { // Trying to get more types for verify if the window have any other type winType = winfo.windowType(~types & NET::AllTypesMask); if (winType == -1) { qWarning() << KWindowInfo(winfo.win(), 0, NET::WM2WindowClass).windowClassName() << "doesn't have any WindowType, assuming as NET::Normal"; return true; } } return !((winType & NET::Menu) || (winType & NET::Dock) || (winType & NET::Splash)); } void XWindowInterface::windowChangedProxy(WId wid, NET::Properties prop1, NET::Properties2 prop2) { //! if the view changed is ignored if (std::find(m_views.cbegin(), m_views.cend(), wid) != m_views.cend()) return; const auto winType = KWindowInfo(wid, NET::WMWindowType).windowType(NET::DesktopMask); //! update desktop id if (winType != -1 && (winType & NET::Desktop)) { m_desktopId = wid; emit windowChanged(wid); return; } //! accept only NET::Properties events, //! ignore when the user presses a key, or a window is sending X events etc. //! without needing to (e.g. Firefox, https://bugzilla.mozilla.org/show_bug.cgi?id=1389953) //! NET::WM2UserTime, NET::WM2IconPixmap etc.... if (prop1 == 0) { return; } //! accepty only the following NET:Properties changed signals //! NET::WMState, NET::WMGeometry, NET::ActiveWindow if (!((prop1 & NET::WMState) || (prop1 & NET::WMGeometry) || (prop1 & NET::ActiveWindow))) { return; } //! when only WMState changed we can whitelist the acceptable states if ((prop1 & NET::WMState) && !(prop1 & NET::WMGeometry) && !(prop1 & NET::ActiveWindow)) { KWindowInfo info(wid, NET::WMState); if (info.valid()) { if (!info.hasState(NET::Sticky) && !info.hasState(NET::Shaded) && !info.hasState(NET::FullScreen) && !info.hasState(NET::Hidden)) { return; } } else { return; } } emit windowChanged(wid); } } diff --git a/containmentactions/contextmenu/menu.cpp b/containmentactions/contextmenu/menu.cpp index daf3330d..475377a1 100644 --- a/containmentactions/contextmenu/menu.cpp +++ b/containmentactions/contextmenu/menu.cpp @@ -1,214 +1,214 @@ /* * Copyright 2018 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 "menu.h" // local -#include "../../liblattedock/dock.h" +#include "../../liblatte2/types.h" // Qt #include #include #include #include #include #include // KDE #include #include // Plasma #include #include #include Menu::Menu(QObject *parent, const QVariantList &args) : Plasma::ContainmentActions(parent, args) { makeActions(); } Menu::~Menu() { m_separator1->deleteLater(); m_addWidgetsAction->deleteLater(); m_configureAction->deleteLater(); m_printAction->deleteLater(); m_switchLayoutsMenu->deleteLater(); m_layoutsAction->deleteLater(); } void Menu::makeActions() { m_separator1 = new QAction(this); m_separator1->setSeparator(true); m_printAction = new QAction(QIcon::fromTheme("edit"), "Print Message...", this); connect(m_printAction, &QAction::triggered, [ = ]() { qDebug() << "Action Trigerred !!!"; }); m_addWidgetsAction = new QAction(QIcon::fromTheme("add"), i18n("Add Widgets..."), this); m_addWidgetsAction->setStatusTip(i18n("Show Plasma Widget Explorer")); connect(m_addWidgetsAction, &QAction::triggered, [ = ]() { QDBusInterface iface("org.kde.plasmashell", "/PlasmaShell", "", QDBusConnection::sessionBus()); if (iface.isValid()) { iface.call("toggleWidgetExplorer"); } }); m_configureAction = new QAction(QIcon::fromTheme("configure"), i18nc("dock/panel settings window", "Dock/Panel Settings"), this); m_configureAction->setShortcut(QKeySequence()); connect(m_configureAction, &QAction::triggered, this, &Menu::requestConfiguration); m_switchLayoutsMenu = new QMenu; m_layoutsAction = m_switchLayoutsMenu->menuAction(); m_layoutsAction->setText(i18n("Layouts")); m_layoutsAction->setIcon(QIcon::fromTheme("user-identity")); m_layoutsAction->setStatusTip(i18n("Switch to another layout")); connect(m_switchLayoutsMenu, &QMenu::aboutToShow, this, &Menu::populateLayouts); connect(m_switchLayoutsMenu, &QMenu::triggered, this, &Menu::switchToLayout); } void Menu::requestConfiguration() { if (this->containment()) { emit this->containment()->configureRequested(containment()); } } QList Menu::contextualActions() { QList actions; actions << m_separator1; //actions << m_printAction; actions << m_layoutsAction; actions << m_addWidgetsAction; actions << m_configureAction; m_layoutsData.clear(); QDBusInterface iface("org.kde.lattedock", "/Latte", "", QDBusConnection::sessionBus()); if (iface.isValid()) { QDBusReply replyData = iface.call("contextMenuData"); m_layoutsData = replyData.value(); } if (m_layoutsData.size() > 3) { m_layoutsAction->setEnabled(true); m_layoutsAction->setVisible(true); } else { m_layoutsAction->setVisible(false); } return actions; } QAction *Menu::action(const QString &name) { if (name == "add widgets") { return m_addWidgetsAction; } else if (name == "configure") { return m_configureAction; } else if (name == "layouts") { return m_layoutsAction; } return nullptr; } void Menu::populateLayouts() { m_switchLayoutsMenu->clear(); if (m_layoutsData.size() > 3) { //when there are more than 1 layouts present - Latte::Dock::LayoutsMemoryUsage memoryUsage = static_cast((m_layoutsData[0]).toInt()); + Latte::Types::LayoutsMemoryUsage memoryUsage = static_cast((m_layoutsData[0]).toInt()); QString currentName = m_layoutsData[1]; for (int i = 2; i < m_layoutsData.size(); ++i) { bool isActive = m_layoutsData[i].startsWith("0") ? false : true; QString layout = m_layoutsData[i].right(m_layoutsData[i].length() - 2); - QString currentText = (memoryUsage == Latte::Dock::MultipleLayouts && layout == currentName) ? + QString currentText = (memoryUsage == Latte::Types::MultipleLayouts && layout == currentName) ? (" " + i18nc("current layout", "(Current)")) : ""; QString layoutName = layout + currentText; QAction *layoutAction = new QAction(layoutName, m_switchLayoutsMenu); layoutAction->setCheckable(true); if (isActive) { layoutAction->setChecked(true); } else { layoutAction->setChecked(false); } layoutAction->setData(layout); if (isActive) { QFont font = layoutAction->font(); font.setBold(true); layoutAction->setFont(font); } m_switchLayoutsMenu->addAction(layoutAction); } m_switchLayoutsMenu->addSeparator(); QAction *editLayoutsAction = new QAction(i18n("Configure..."), m_switchLayoutsMenu); editLayoutsAction->setData(QStringLiteral(" _show_latte_settings_dialog_")); m_switchLayoutsMenu->addAction(editLayoutsAction); } } void Menu::switchToLayout(QAction *action) { const QString layout = action->data().toString(); if (layout == " _show_latte_settings_dialog_") { QTimer::singleShot(400, [this]() { QDBusInterface iface("org.kde.lattedock", "/Latte", "", QDBusConnection::sessionBus()); if (iface.isValid()) { - iface.call("showSettingsWindow", (int)Latte::Dock::LayoutPage); + iface.call("showSettingsWindow", (int)Latte::Types::LayoutPage); } }); } else { QTimer::singleShot(400, [this, layout]() { QDBusInterface iface("org.kde.lattedock", "/Latte", "", QDBusConnection::sessionBus()); if (iface.isValid()) { iface.call("switchToLayout", layout); } }); } } K_EXPORT_PLASMA_CONTAINMENTACTIONS_WITH_JSON(lattecontextmenu, Menu, "plasma-containmentactions-lattecontextmenu.json") #include "menu.moc"