diff --git a/app/layout.cpp b/app/layout.cpp index 77ae5564..7e4538dd 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) { addContainment(containment); } else if (m_corona->layoutManager()->memoryUsage() == Dock::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()) { kwin_setDisabledMaximizedBorders(disableBordersForMaximizedWindows()); } else if (m_corona->layoutManager()->memoryUsage() == Dock::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) { 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) { m_containments.append(containment); containmentInLayout = true; } else if (m_corona->layoutManager()->memoryUsage() == Dock::MultipleLayouts) { QString layoutId = containment->config().readEntry("layoutId", QString()); if (!layoutId.isEmpty() && (layoutId == m_layoutName)) { m_containments.append(containment); containmentInLayout = true; } } if (containmentInLayout) { if (!blockAutomaticLatteViewCreation()) { addDock(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) { return {"0"}; } else if (m_corona->layoutManager()->memoryUsage() == Dock::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_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::addDock(Plasma::Containment *containment, bool forceOnPrimary, int expDockScreen) { qDebug() << "Layout :::: " << m_layoutName << " ::: addDock 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 && expDockScreen == -1) { id = containment->lastScreen(); } if (expDockScreen > -1) { id = expDockScreen; } 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))); - bool dockWin{true}; + bool byPassWM{false}; if (mode == Dock::AlwaysVisible || mode == Dock::WindowsGoBelow) { - dockWin = true; + byPassWM = false; } else { - dockWin = containment->config().readEntry("dockWindowBehavior", true); + byPassWM = containment->config().readEntry("byPassWM", false); } - auto latteView = new Latte::View(m_corona, nextScreen, dockWin); + 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::dockLocationChanged); connect(containment, &Plasma::Containment::appletAlternativesRequested , m_corona, &Latte::Corona::showAlternativesForApplet, Qt::QueuedConnection); if (m_corona->layoutManager()->memoryUsage() == Dock::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::addNewDock() { if (!m_corona) { return; } m_corona->loadDefaultLayout(); } void Layout::copyDock(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; addDock(newContainment, false, copyScrId); newContainment->reactToScreenChange(); } else { qDebug() << "Copy Dock in current screen..."; addDock(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) { 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::recreateDock(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(); addDock(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); addDock(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) { 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) { 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/view/dockconfigview.cpp b/app/view/dockconfigview.cpp index 9f2909ce..240608fb 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, SIGNAL(raiseDocksTemporaryChanged()), this, SIGNAL(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()->setDockExtraFlags(*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 previousDockWinBehavior = (m_latteView->flags() & Qt::BypassWindowManagerHint) ? false : true; + const auto previousByPassWMBehavior = (m_latteView->flags() & Qt::BypassWindowManagerHint) ? true : false; if (mode == Dock::AlwaysVisible || mode == Dock::WindowsGoBelow) { - if (!previousDockWinBehavior) { + if (!previousByPassWMBehavior) { m_latteView->managedLayout()->recreateDock(m_latteView->containment()); } - } else if (m_latteView->dockWinBehavior() != previousDockWinBehavior) { + } else if (m_latteView->byPassWM() != previousByPassWMBehavior) { m_latteView->managedLayout()->recreateDock(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; //! 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())) { 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) { m_latteView->managedLayout()->setLaunchers(launchers.toStringList()); } else if (group == Dock::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/view.cpp b/app/view/view.cpp index 7aef45d1..f69d48f9 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" // Qt #include #include #include #include #include #include // KDe #include #include #include #include #include // Plasma #include #include #include namespace Latte { -//! both alwaysVisible and dockWinBehavior are passed through corona because -//! during the dock window creation containment hasn't been set, but these variables +//! 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 dockWindowBehavior) +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 (dockWindowBehavior) { - setFlags(flags); - } else { + 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, [ &, dockWindowBehavior]() { + , 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 - setDockWinBehavior(dockWindowBehavior); + 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::dockLocationChanged, 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::dockWinBehaviorChanged, this, &View::saveConfig); + 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::copyDock() { m_managedLayout->copyDock(containment()); } void View::removeDock() { 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) { 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::dockWinBehavior() const +bool View::byPassWM() const { - return m_dockWinBehavior; + return m_byPassWM; } -void View::setDockWinBehavior(bool dock) +void View::setByPassWM(bool bypass) { - if (m_dockWinBehavior == dock) { + if (m_byPassWM == bypass) { return; } - m_dockWinBehavior = dock; - emit dockWinBehaviorChanged(); + 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); 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) { 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("dockWindowBehavior", dockWinBehavior()); + 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_dockWinBehavior = config.readEntry("dockWindowBehavior", 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 dockWinBehaviorChanged(); + emit byPassWMChanged(); } //!END configuration functions } //!END namespace diff --git a/app/view/view.h b/app/view/view.h index a3d86ed4..a2a9b3ed 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" // 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) - Q_PROPERTY(bool dockWinBehavior READ dockWinBehavior WRITE setDockWinBehavior NOTIFY dockWinBehaviorChanged) //! 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 dockWindowBehavior = false); + 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 dockWinBehavior() const; - void setDockWinBehavior(bool dock); + 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 removeDock(); Q_INVOKABLE void copyDock(); 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 dockWinBehaviorChanged(); 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_dockWinBehavior{true}; + 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}; 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/shell/package/contents/configuration/TweaksConfig.qml b/shell/package/contents/configuration/TweaksConfig.qml index 9d6b0837..f4c469bc 100644 --- a/shell/package/contents/configuration/TweaksConfig.qml +++ b/shell/package/contents/configuration/TweaksConfig.qml @@ -1,311 +1,311 @@ /* * Copyright 2016 Smith AR * Michail Vourlakos * * This file is part of Latte-Dock * * Latte-Dock is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * Latte-Dock is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ import QtQuick 2.0 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.3 import QtGraphicalEffects 1.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.plasma.plasmoid 2.0 import org.kde.latte 0.1 as Latte PlasmaComponents.Page { Layout.maximumWidth: content.width + content.Layout.leftMargin * 2 Layout.maximumHeight: content.height + units.smallSpacing * 2 ColumnLayout { id: content width: (dialog.appliedWidth - units.smallSpacing * 2) - Layout.leftMargin * 2 spacing: dialog.subGroupSpacing anchors.horizontalCenter: parent.horizontalCenter Layout.leftMargin: units.smallSpacing * 2 Layout.rightMargin: units.smallSpacing * 2 //! BEGIN: Appearance ColumnLayout { spacing: units.smallSpacing Layout.rightMargin: units.smallSpacing * 2 Layout.topMargin: units.smallSpacing Header { text: i18n("Appearance") } PlasmaComponents.CheckBox { id: blurPanel Layout.leftMargin: units.smallSpacing * 2 text: i18n("Blur for panel background") checked: plasmoid.configuration.blurEnabled onClicked: { plasmoid.configuration.blurEnabled = checked } } PlasmaComponents.CheckBox { id: titleTooltipsChk Layout.leftMargin: units.smallSpacing * 2 text: i18n("Show applets/task title tooltips on hovering") checked: plasmoid.configuration.titleTooltips onClicked: { plasmoid.configuration.titleTooltips = checked; } } PlasmaComponents.CheckBox { id: shrinkThickness Layout.leftMargin: units.smallSpacing * 2 text: i18n("Shrink thickness margins to minimum") checked: plasmoid.configuration.shrinkThickMargins onClicked: { plasmoid.configuration.shrinkThickMargins = checked } } } //! END: Appearance //! BEGIN: Dynamic Background ColumnLayout { spacing: units.smallSpacing Layout.rightMargin: units.smallSpacing * 2 enabled: Latte.WindowSystem.compositingActive Header { text: i18n("Dynamic Background") } PlasmaComponents.CheckBox { id: solidForMaximizedChk Layout.leftMargin: units.smallSpacing * 2 Layout.maximumWidth: (dialog.appliedWidth - units.smallSpacing * 2) - 3*units.smallSpacing text: i18n("Force solid background for maximized or snapped windows") checked: plasmoid.configuration.solidBackgroundForMaximized tooltip: i18n("The panel background removes its transparency setting \n when there is a maximized or snapped window") style: LatteCheckBoxStyle{} onClicked: { plasmoid.configuration.solidBackgroundForMaximized = checked; } } PlasmaComponents.CheckBox { id: onlyOnMaximizedChk Layout.leftMargin: units.smallSpacing * 2 text: i18n("Hide background for not maximized windows") checked: plasmoid.configuration.backgroundOnlyOnMaximized tooltip: i18n("The panel background becomes transparent except if \nthere is a maximized or snapped window") onClicked: { plasmoid.configuration.backgroundOnlyOnMaximized = checked; } } PlasmaComponents.CheckBox { id: colorizeTransparentPanelsChk Layout.leftMargin: units.smallSpacing * 2 Layout.maximumWidth: (dialog.appliedWidth - units.smallSpacing * 2) - units.smallSpacing * 3 text: i18n("Monochrome contents when panel is transparent") checked: plasmoid.configuration.colorizeTransparentPanels tooltip: i18n("The panel contents are colorized in order to improve contrast \nwith the underlying desktop background when the panel is transparent") style: LatteCheckBoxStyle{} enabled: solidForMaximizedChk.checked || onlyOnMaximizedChk.checked onClicked: { plasmoid.configuration.colorizeTransparentPanels = checked; } } PlasmaComponents.CheckBox { id: colorizeFromActiveWindowSchemeChk Layout.leftMargin: units.smallSpacing * 2 Layout.maximumWidth: (dialog.appliedWidth - units.smallSpacing * 2) - units.smallSpacing * 3 text: i18n("Paint contents based on active window scheme") checked: plasmoid.configuration.colorizeFromActiveWindowScheme tooltip: i18n("The panel contents are colorized from active window scheme \nwhen that window is maximized or is touching the panel.") style: LatteCheckBoxStyle{} enabled: solidForMaximizedChk.checked || onlyOnMaximizedChk.checked onClicked: { plasmoid.configuration.colorizeFromActiveWindowScheme = checked; } } PlasmaComponents.CheckBox { id: hideShadowsOnMaximizedChk Layout.leftMargin: units.smallSpacing * 2 text: i18n("Hide panel shadow for maximized windows") checked: plasmoid.configuration.disablePanelShadowForMaximized onClicked: { plasmoid.configuration.disablePanelShadowForMaximized = checked; } } } //! END: Dynamic Background //! BEGIN: Behavior ColumnLayout { spacing: units.smallSpacing Layout.rightMargin: units.smallSpacing * 2 Header { text: i18n("Behavior") } PlasmaComponents.CheckBox { Layout.leftMargin: units.smallSpacing * 2 text: i18n("Activate KWin edge after hiding") checked: dock.visibility.enableKWinEdges onClicked: { dock.visibility.enableKWinEdges = checked; } } PlasmaComponents.CheckBox { Layout.leftMargin: units.smallSpacing * 2 text: i18n("Decrease applets size when it is needed") checked: plasmoid.configuration.autoDecreaseIconSize tooltip: i18n("Applets size is decreased automatically when the contents \nexceed the maximum length \n\nHint: this option is disabled when only plasma taskmanagers are present") enabled: !(dock.tasksPresent() && !dock.latteTasksPresent()); onClicked: { plasmoid.configuration.autoDecreaseIconSize = checked } } PlasmaComponents.CheckBox { Layout.leftMargin: units.smallSpacing * 2 text: i18n("Add launchers only in the corresponding area") checked: plasmoid.configuration.addLaunchersInTaskManager tooltip: i18n("Launchers are added only in the taskmanager and not as plasma applets") onClicked: { plasmoid.configuration.addLaunchersInTaskManager = checked; } } PlasmaComponents.CheckBox { Layout.leftMargin: units.smallSpacing * 2 text: i18n("Prefer for global shortcuts activation") checked: dock.isPreferredForShortcuts tooltip: i18n("Enable highest priority for global shortcuts activation") onClicked: { dock.isPreferredForShortcuts = checked } } PlasmaComponents.CheckBox { Layout.leftMargin: units.smallSpacing * 2 - text: i18n("Behave as a normal dock window") - checked: dock.dockWinBehavior + text: i18n("Above fullscreen windows") + checked: dock.byPassWM enabled: !(dock.visibility.mode === Latte.Dock.AlwaysVisible || dock.visibility.mode === Latte.Dock.WindowsGoBelow) - tooltip: i18n("Remove the BypassWindowManagerHint flag from the window.\nThe dock wont be above windows which are set at 'Always On Top'") + tooltip: i18n("BypassWindowManagerHint flag for the window.\nThe view will be above all windows even those set as 'Always On Top'") onCheckedChanged: { - dock.dockWinBehavior = checked + dock.byPassWM = checked; } } PlasmaComponents.CheckBox { Layout.leftMargin: units.smallSpacing * 2 text: i18n("Raise on desktop change") checked: dock.visibility.raiseOnDesktop enabled: dock.visibility.mode !== Latte.Dock.AlwaysVisible onClicked: { dock.visibility.raiseOnDesktop = checked } } PlasmaComponents.CheckBox { Layout.leftMargin: units.smallSpacing * 2 text: i18n("Raise on activity change") checked: dock.visibility.raiseOnActivity enabled: dock.visibility.mode !== Latte.Dock.AlwaysVisible onClicked: { dock.visibility.raiseOnActivity = checked } } } //! END: Behavior //! BEGIN: Extra Actions ColumnLayout { Layout.fillWidth: true spacing: units.smallSpacing Layout.rightMargin: units.smallSpacing * 2 Header { text: i18n("Extra Actions") } RowLayout { Layout.fillWidth: true Layout.leftMargin: units.smallSpacing * 2 spacing: units.smallSpacing PlasmaComponents.Button { iconSource: "distribute-horizontal-x" text: i18n("Add Spacer") Layout.minimumWidth: 0.5 * (content.width - 5 * units.smallSpacing) Layout.maximumWidth: Layout.minimumWidth Layout.alignment: Qt.AlignLeft tooltip: i18n("Add a spacer to separate applets") onClicked: { dockConfig.addPanelSpacer() } } PlasmaComponents.Button { Layout.fillWidth: true iconSource: "edit-delete" text: i18n("Remove Tasks Applet") enabled: dock.tasksPresent() tooltip: i18n("Remove Latte Tasks plasmoid") onClicked: { dock.removeTasksPlasmoid(); } } } } //! END: Extra Actions //! Bottom spacer PlasmaComponents.Label{ id: bottomMarginSpacer text:" " } } }