File indexing completed on 2024-04-21 16:17:06

0001 /*
0002 *  Copyright 2017  Smith AR <audoban@openmailbox.org>
0003 *                  Michail Vourlakos <mvourlakos@gmail.com>
0004 *
0005 *  This file is part of Latte-Dock
0006 *
0007 *  Latte-Dock is free software; you can redistribute it and/or
0008 *  modify it under the terms of the GNU General Public License as
0009 *  published by the Free Software Foundation; either version 2 of
0010 *  the License, or (at your option) any later version.
0011 *
0012 *  Latte-Dock is distributed in the hope that it will be useful,
0013 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0014 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0015 *  GNU General Public License for more details.
0016 *
0017 *  You should have received a copy of the GNU General Public License
0018 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
0019 */
0020 
0021 #include "centrallayout.h"
0022 
0023 // local
0024 #include "sharedlayout.h"
0025 #include "../lattecorona.h"
0026 #include "../screenpool.h"
0027 #include "../layouts/importer.h"
0028 #include "../layouts/manager.h"
0029 #include "../layouts/synchronizer.h"
0030 #include "../settings/universalsettings.h"
0031 #include "../view/view.h"
0032 #include "../../liblatte2/types.h"
0033 
0034 // KDE
0035 #include <KConfigGroup>
0036 #include <KActivities/Consumer>
0037 
0038 namespace Latte {
0039 
0040 CentralLayout::CentralLayout(QObject *parent, QString layoutFile, QString assignedName)
0041     : Layout::GenericLayout(parent, layoutFile, assignedName)
0042 {
0043     if (m_loadedCorrectly) {
0044         loadConfig();
0045         init();
0046     }
0047 }
0048 
0049 CentralLayout::~CentralLayout()
0050 {
0051     if (!m_layoutFile.isEmpty()) {
0052         m_layoutGroup.sync();
0053     }
0054 }
0055 
0056 void CentralLayout::unloadContainments()
0057 {
0058     Layout::GenericLayout::unloadContainments();
0059 
0060     if (m_sharedLayout) {
0061         disconnectSharedConnections();
0062         m_sharedLayout->removeCentralLayout(this);
0063     }
0064 }
0065 
0066 void CentralLayout::init()
0067 {
0068     connect(this, &CentralLayout::activitiesChanged, this, &CentralLayout::saveConfig);
0069     connect(this, &CentralLayout::disableBordersForMaximizedWindowsChanged, this, &CentralLayout::saveConfig);
0070     connect(this, &CentralLayout::sharedLayoutNameChanged, this, &CentralLayout::saveConfig);
0071     connect(this, &CentralLayout::showInMenuChanged, this, &CentralLayout::saveConfig);
0072 }
0073 
0074 void CentralLayout::initToCorona(Latte::Corona *corona)
0075 {
0076     if (GenericLayout::initToCorona(corona)) {
0077         connect(m_corona->universalSettings(), &UniversalSettings::canDisableBordersChanged, this, [&]() {
0078             if (m_corona->universalSettings()->canDisableBorders()) {
0079                 kwin_setDisabledMaximizedBorders(disableBordersForMaximizedWindows());
0080             } else {
0081                 kwin_setDisabledMaximizedBorders(false);
0082             }
0083         });
0084 
0085 
0086         if (m_corona->layoutsManager()->memoryUsage() == Types::SingleLayout && m_corona->universalSettings()->canDisableBorders()) {
0087             kwin_setDisabledMaximizedBorders(disableBordersForMaximizedWindows());
0088         } else if (m_corona->layoutsManager()->memoryUsage() == Types::MultipleLayouts) {
0089             connect(m_corona->layoutsManager(), &Layouts::Manager::currentLayoutNameChanged, this, [&]() {
0090                 if (m_corona->universalSettings()->canDisableBorders()
0091                     && m_corona->layoutsManager()->currentLayoutName() == name()) {
0092                     kwin_setDisabledMaximizedBorders(disableBordersForMaximizedWindows());
0093                 }
0094             });
0095         }
0096 
0097         //! Request the SharedLayout in case there is one and Latte is functioning in MultipleLayouts mode
0098         if (m_corona->layoutsManager()->memoryUsage() == Types::MultipleLayouts && !m_sharedLayoutName.isEmpty()) {
0099             if (m_corona->layoutsManager()->synchronizer()->registerAtSharedLayout(this, m_sharedLayoutName)) {
0100                 setSharedLayout(m_corona->layoutsManager()->synchronizer()->sharedLayout(m_sharedLayoutName));
0101             }
0102         }
0103     }
0104 }
0105 
0106 bool CentralLayout::disableBordersForMaximizedWindows() const
0107 {
0108     return m_disableBordersForMaximizedWindows;
0109 }
0110 
0111 void CentralLayout::setDisableBordersForMaximizedWindows(bool disable)
0112 {
0113     if (m_disableBordersForMaximizedWindows == disable) {
0114         return;
0115     }
0116 
0117     m_disableBordersForMaximizedWindows = disable;
0118     kwin_setDisabledMaximizedBorders(disable);
0119 
0120     emit disableBordersForMaximizedWindowsChanged();
0121 }
0122 
0123 bool CentralLayout::kwin_disabledMaximizedBorders() const
0124 {
0125     if (!m_corona) {
0126         return false;
0127     }
0128 
0129     return m_corona->universalSettings()->kwin_borderlessMaximizedWindowsEnabled();
0130 }
0131 
0132 void CentralLayout::kwin_setDisabledMaximizedBorders(bool disable)
0133 {
0134     if (!m_corona) {
0135         return;
0136     }
0137 
0138     m_corona->universalSettings()->kwin_setDisabledMaximizedBorders(disable);
0139 }
0140 
0141 bool CentralLayout::showInMenu() const
0142 {
0143     return m_showInMenu;
0144 }
0145 
0146 void CentralLayout::setShowInMenu(bool show)
0147 {
0148     if (m_showInMenu == show) {
0149         return;
0150     }
0151 
0152     m_showInMenu = show;
0153     emit showInMenuChanged();
0154 }
0155 
0156 Layout::Type CentralLayout::type() const
0157 {
0158     return Layout::Type::Central;
0159 }
0160 
0161 QStringList CentralLayout::activities() const
0162 {
0163     return m_activities;
0164 }
0165 
0166 void CentralLayout::setActivities(QStringList activities)
0167 {
0168     if (m_activities == activities) {
0169         return;
0170     }
0171 
0172     m_activities = activities;
0173 
0174     emit activitiesChanged();
0175 }
0176 
0177 QString CentralLayout::sharedLayoutName() const
0178 {
0179     return m_sharedLayoutName;
0180 }
0181 
0182 void CentralLayout::setSharedLayoutName(QString name)
0183 {
0184     if (m_sharedLayoutName == name || (!Layouts::Importer::layoutExists(name) && !name.isEmpty())) {
0185         return;
0186     }
0187 
0188     m_sharedLayoutName = name;
0189     emit sharedLayoutNameChanged();
0190 }
0191 
0192 SharedLayout *CentralLayout::sharedLayout() const
0193 {
0194     return m_sharedLayout;
0195 }
0196 
0197 void CentralLayout::setSharedLayout(SharedLayout *layout)
0198 {
0199     if (m_sharedLayout == layout) {
0200         return;
0201     }
0202 
0203     disconnectSharedConnections();
0204 
0205     m_sharedLayout = layout;
0206 
0207     if (layout) {
0208         setSharedLayoutName(m_sharedLayout->name());
0209 
0210         //! attach new signals
0211         m_sharedConnections << connect(m_sharedLayout, &Layout::GenericLayout::viewsCountChanged, this, &Layout::GenericLayout::viewsCountChanged);
0212         m_sharedConnections << connect(m_sharedLayout, &Layout::AbstractLayout::nameChanged, this, [this]() {
0213             setSharedLayoutName(m_sharedLayout->name());
0214         });
0215         m_sharedConnections << connect(m_sharedLayout, &Layout::GenericLayout::viewEdgeChanged, this, [this]() {
0216             syncLatteViewsToScreens();
0217         });
0218     } else {
0219         setSharedLayoutName(QString());
0220     }
0221 
0222     syncLatteViewsToScreens();
0223     emit viewsCountChanged();
0224 }
0225 
0226 void CentralLayout::disconnectSharedConnections()
0227 {
0228     //! drop old signals
0229     for (const auto &sc : m_sharedConnections) {
0230         QObject::disconnect(sc);
0231     }
0232 
0233     m_sharedConnections.clear();
0234 }
0235 
0236 void CentralLayout::loadConfig()
0237 {
0238     m_disableBordersForMaximizedWindows = m_layoutGroup.readEntry("disableBordersForMaximizedWindows", false);
0239     m_showInMenu = m_layoutGroup.readEntry("showInMenu", false);     
0240     m_activities = m_layoutGroup.readEntry("activities", QStringList());
0241 
0242     QString sharedLayoutName = m_layoutGroup.readEntry("sharedLayout", QString());
0243 
0244     if (Layouts::Importer::layoutExists(sharedLayoutName)) {
0245         m_sharedLayoutName = sharedLayoutName;
0246     }
0247 
0248     emit activitiesChanged();
0249 }
0250 
0251 void CentralLayout::saveConfig()
0252 {
0253     qDebug() << "CENTRAL layout is saving... for layout:" << m_layoutName;
0254     m_layoutGroup.writeEntry("showInMenu", m_showInMenu);
0255     m_layoutGroup.writeEntry("disableBordersForMaximizedWindows", m_disableBordersForMaximizedWindows);
0256     m_layoutGroup.writeEntry("sharedLayout", m_sharedLayoutName);
0257     m_layoutGroup.writeEntry("activities", m_activities);
0258 
0259     m_layoutGroup.sync();
0260 }
0261 
0262 //! OVERRIDES
0263 
0264 void CentralLayout::addView(Plasma::Containment *containment, bool forceOnPrimary, int explicitScreen, Layout::ViewsMap *occupied)
0265 {
0266     if (m_sharedLayout) {
0267         //! consider already occupied edges from SharedLayout
0268         Layout::ViewsMap ocMap = m_sharedLayout->validViewsMap();
0269         qDebug() << " HIGH PRIORITY ALREADY OCCUPIED EDGES :: " << ocMap;
0270         Layout::GenericLayout::addView(containment, forceOnPrimary, explicitScreen, &ocMap);
0271     } else {
0272         Layout::GenericLayout::addView(containment, forceOnPrimary, explicitScreen, occupied);
0273     }
0274 }
0275 
0276 bool CentralLayout::configViewIsShown() const
0277 {
0278     bool genericShown = GenericLayout::configViewIsShown();
0279     if (m_sharedLayout) {
0280         return (m_sharedLayout->configViewIsShown() || genericShown);
0281     }
0282 
0283     return genericShown;
0284 }
0285 
0286 const QStringList CentralLayout::appliedActivities()
0287 {
0288     if (!m_corona) {
0289         return {};
0290     }
0291 
0292     if (m_corona->layoutsManager()->memoryUsage() == Types::SingleLayout) {
0293         return {"0"};
0294     } else if (m_corona->layoutsManager()->memoryUsage() == Types::MultipleLayouts) {
0295         if (m_activities.isEmpty()) {
0296             return m_corona->layoutsManager()->synchronizer()->orphanedActivities();
0297         } else {
0298             return m_activities;
0299         }
0300     } else {
0301         return {"0"};
0302     }
0303 }
0304 
0305 QList<Latte::View *> CentralLayout::latteViews()
0306 {
0307     if (m_sharedLayout) {
0308         QList<Latte::View *> views = Layout::GenericLayout::latteViews();
0309         views << m_sharedLayout->latteViews();
0310 
0311         return views;
0312     }
0313 
0314     return Layout::GenericLayout::latteViews();
0315 }
0316 
0317 int CentralLayout::viewsCount(int screen) const
0318 {
0319     if (!m_corona) {
0320         return 0;
0321     }
0322 
0323     int views = Layout::GenericLayout::viewsCount(screen);
0324 
0325     if (m_sharedLayout) {
0326         QScreen *scr = m_corona->screenPool()->screenForId(screen);
0327 
0328         for (const auto view : m_sharedLayout->latteViews()) {
0329             if (view && view->screen() == scr && !view->containment()->destroyed()) {
0330                 ++views;
0331             }
0332         }
0333     }
0334 
0335     return views;
0336 }
0337 
0338 int CentralLayout::viewsCount(QScreen *screen) const
0339 {
0340     if (!m_corona) {
0341         return 0;
0342     }
0343 
0344     int views = Layout::GenericLayout::viewsCount(screen);
0345 
0346     if (m_sharedLayout) {
0347         for (const auto view : m_sharedLayout->latteViews()) {
0348             if (view && view->screen() == screen && !view->containment()->destroyed()) {
0349                 ++views;
0350             }
0351         }
0352     }
0353 
0354     return views;
0355 }
0356 
0357 int CentralLayout::viewsCount() const
0358 {
0359     if (!m_corona) {
0360         return 0;
0361     }
0362 
0363     int views = Layout::GenericLayout::viewsCount();
0364 
0365     if (m_sharedLayout) {
0366         for (const auto view : m_sharedLayout->latteViews()) {
0367             if (view && view->containment() && !view->containment()->destroyed()) {
0368                 ++views;
0369             }
0370         }
0371     }
0372 
0373     return views;
0374 }
0375 
0376 QList<Plasma::Types::Location> CentralLayout::availableEdgesForView(QScreen *scr, Latte::View *forView) const
0377 {
0378     using Plasma::Types;
0379     QList<Types::Location> edges{Types::BottomEdge, Types::LeftEdge,
0380                 Types::TopEdge, Types::RightEdge};
0381 
0382     if (!m_corona) {
0383         return edges;
0384     }
0385 
0386     edges = Layout::GenericLayout::availableEdgesForView(scr, forView);
0387 
0388     if (m_sharedLayout) {
0389         for (const auto view : m_sharedLayout->latteViews()) {
0390             //! make sure that availabe edges takes into account only views that should be excluded,
0391             //! this is why the forView should not be excluded
0392             if (view && view != forView && view->positioner()->currentScreenName() == scr->name()) {
0393                 edges.removeOne(view->location());
0394             }
0395         }
0396     }
0397 
0398     return edges;
0399 }
0400 
0401 QList<Plasma::Types::Location> CentralLayout::freeEdges(QScreen *scr) const
0402 {
0403     using Plasma::Types;
0404     QList<Types::Location> edges{Types::BottomEdge, Types::LeftEdge,
0405                 Types::TopEdge, Types::RightEdge};
0406 
0407     if (!m_corona) {
0408         return edges;
0409     }
0410 
0411     edges = Layout::GenericLayout::freeEdges(scr);
0412 
0413     if (m_sharedLayout) {
0414         for (const auto view : m_sharedLayout->latteViews()) {
0415             if (view && view->positioner()->currentScreenName() == scr->name()) {
0416                 edges.removeOne(view->location());
0417             }
0418         }
0419     }
0420 
0421     return edges;
0422 }
0423 
0424 QList<Plasma::Types::Location> CentralLayout::freeEdges(int screen) const
0425 {
0426     using Plasma::Types;
0427     QList<Types::Location> edges{Types::BottomEdge, Types::LeftEdge,
0428                 Types::TopEdge, Types::RightEdge};
0429 
0430     if (!m_corona) {
0431         return edges;
0432     }
0433 
0434     edges = Layout::GenericLayout::freeEdges(screen);
0435     QScreen *scr = m_corona->screenPool()->screenForId(screen);
0436 
0437     if (m_sharedLayout) {
0438         for (const auto view : m_sharedLayout->latteViews()) {
0439             if (view && scr && view->positioner()->currentScreenName() == scr->name()) {
0440                 edges.removeOne(view->location());
0441             }
0442         }
0443     }
0444 
0445     return edges;
0446 }
0447 
0448 Types::ViewType CentralLayout::latteViewType(int containmentId) const
0449 {
0450     for (const auto view : m_latteViews) {
0451         if (view->containment() && view->containment()->id() == containmentId) {
0452             return view->type();
0453         }
0454     }
0455 
0456     if (m_sharedLayout) {
0457         return m_sharedLayout->latteViewType(containmentId);
0458     }
0459 
0460     return Types::DockView;
0461 }
0462 
0463 QList<Latte::View *> CentralLayout::sortedLatteViews(QList<Latte::View *> views)
0464 {
0465     QList<Latte::View *> vws = latteViews();
0466 
0467     return Layout::GenericLayout::sortedLatteViews(vws);
0468 }
0469 
0470 QList<Latte::View *> CentralLayout::viewsWithPlasmaShortcuts()
0471 {
0472     QList<Latte::View *> combined = Layout::GenericLayout::viewsWithPlasmaShortcuts();
0473 
0474     if (m_sharedLayout) {
0475         combined << m_sharedLayout->viewsWithPlasmaShortcuts();
0476     }
0477 
0478     return combined;
0479 }
0480 
0481 void CentralLayout::syncLatteViewsToScreens(Layout::ViewsMap *occupiedMap)
0482 {
0483     if (m_sharedLayout) {
0484         Layout::ViewsMap map = m_sharedLayout->validViewsMap();
0485         Layout::GenericLayout::syncLatteViewsToScreens(&map);
0486     } else {
0487         Layout::GenericLayout::syncLatteViewsToScreens();
0488     }
0489 }
0490 
0491 }