File indexing completed on 2024-12-01 11:10:44
0001 /* 0002 SPDX-FileCopyrightText: 2016 Smith AR <audoban@openmailbox.org> 0003 SPDX-FileCopyrightText: 2016 Michail Vourlakos <mvourlakos@gmail.com> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "view.h" 0009 0010 // local 0011 #include "effects.h" 0012 #include "positioner.h" 0013 #include "visibilitymanager.h" 0014 #include "settings/primaryconfigview.h" 0015 #include "settings/secondaryconfigview.h" 0016 #include "settings/viewsettingsfactory.h" 0017 #include "settings/widgetexplorerview.h" 0018 #include "../apptypes.h" 0019 #include "../lattecorona.h" 0020 #include "../data/layoutdata.h" 0021 #include "../data/viewstable.h" 0022 #include "../declarativeimports/interfaces.h" 0023 #include "../indicator/factory.h" 0024 #include "../layout/genericlayout.h" 0025 #include "../layouts/manager.h" 0026 #include "../layouts/storage.h" 0027 #include "../plasma/extended/theme.h" 0028 #include "../screenpool.h" 0029 #include "../settings/universalsettings.h" 0030 #include "../settings/exporttemplatedialog/exporttemplatedialog.h" 0031 #include "../shortcuts/globalshortcuts.h" 0032 #include "../shortcuts/shortcutstracker.h" 0033 0034 // Qt 0035 #include <QAction> 0036 #include <QDragEnterEvent> 0037 #include <QDragMoveEvent> 0038 #include <QDropEvent> 0039 #include <QMouseEvent> 0040 #include <QQmlContext> 0041 #include <QQmlEngine> 0042 #include <QQmlProperty> 0043 #include <QQuickItem> 0044 #include <QMenu> 0045 0046 // KDe 0047 #include <KActionCollection> 0048 #include <KActivities/Consumer> 0049 #include <KWayland/Client/plasmashell.h> 0050 #include <KWayland/Client/surface.h> 0051 #include <KWindowSystem> 0052 0053 // Plasma 0054 #include <Plasma/Containment> 0055 #include <Plasma/ContainmentActions> 0056 #include <PlasmaQuick/AppletQuickItem> 0057 0058 #define BLOCKHIDINGDRAGTYPE "View::ContainsDrag()" 0059 #define BLOCKHIDINGNEEDSATTENTIONTYPE "View::Containment::NeedsAttentionState()" 0060 #define BLOCKHIDINGREQUESTSINPUTTYPE "View::Containment::RequestsInputState()" 0061 0062 namespace Latte { 0063 0064 //! both alwaysVisible and byPassWMX11 are passed through corona because 0065 //! during the view window creation containment hasn't been set, but these variables 0066 //! are needed in order for window flags to be set correctly 0067 View::View(Plasma::Corona *corona, QScreen *targetScreen, bool byPassX11WM) 0068 : PlasmaQuick::ContainmentView(corona), 0069 m_effects(new ViewPart::Effects(this)), 0070 m_interface(new ViewPart::ContainmentInterface(this)), 0071 m_parabolic(new ViewPart::Parabolic(this)), 0072 m_sink(new ViewPart::EventsSink(this)) 0073 { 0074 //this is disabled because under wayland breaks Views positioning 0075 //setVisible(false); 0076 0077 m_corona = qobject_cast<Latte::Corona *>(corona); 0078 0079 //! needs to be created after Effects because it catches some of its signals 0080 //! and avoid a crash from View::winId() at the same time 0081 m_positioner = new ViewPart::Positioner(this); 0082 0083 // setTitle(corona->kPackage().metadata().name()); 0084 setIcon(qGuiApp->windowIcon()); 0085 setResizeMode(QuickViewSharedEngine::SizeRootObjectToView); 0086 setColor(QColor(Qt::transparent)); 0087 setClearBeforeRendering(true); 0088 0089 const auto flags = Qt::FramelessWindowHint 0090 | Qt::NoDropShadowWindowHint 0091 | Qt::WindowDoesNotAcceptFocus; 0092 0093 if (byPassX11WM) { 0094 setFlags(flags | Qt::BypassWindowManagerHint); 0095 //! needs to be set early enough 0096 m_byPassWM = byPassX11WM; 0097 } else { 0098 setFlags(flags); 0099 } 0100 0101 if (KWindowSystem::isPlatformX11()) { 0102 //! Enable OnAllDesktops during creation in order to protect corner cases that is ignored 0103 //! during startup. Such corner case is bug #447689. 0104 //! Best guess is that this is needed because OnAllDesktops is set through visibilitymanager 0105 //! after containment has been assigned. That delay might lead wm ignoring the flag 0106 //! until it is reapplied. 0107 KWindowSystem::setOnAllDesktops(winId(), true); 0108 } 0109 0110 if (targetScreen) { 0111 m_positioner->setScreenToFollow(targetScreen); 0112 } else { 0113 qDebug() << "org.kde.view :::: corona was found properly!!!"; 0114 m_positioner->setScreenToFollow(m_corona->screenPool()->primaryScreen()); 0115 } 0116 0117 m_releaseGrabTimer.setInterval(400); 0118 m_releaseGrabTimer.setSingleShot(true); 0119 connect(&m_releaseGrabTimer, &QTimer::timeout, this, &View::releaseGrab); 0120 0121 connect(m_interface, &ViewPart::ContainmentInterface::hasExpandedAppletChanged, this, &View::updateTransientWindowsTracking); 0122 0123 connect(this, &View::containmentChanged, this, &View::groupIdChanged); 0124 connect(this, &View::containmentChanged 0125 , this, [ &, byPassX11WM]() { 0126 qDebug() << "dock view c++ containment changed 1..."; 0127 0128 if (!this->containment()) 0129 return; 0130 0131 qDebug() << "dock view c++ containment changed 2..."; 0132 0133 setTitle(validTitle()); 0134 0135 //! First load default values from file 0136 restoreConfig(); 0137 0138 //! Afterwards override that values in case during creation something different is needed 0139 setByPassWM(byPassX11WM); 0140 0141 //! Check the screen assigned to this dock 0142 reconsiderScreen(); 0143 0144 //! needs to be created before visibility creation because visibility uses it 0145 if (!m_windowsTracker) { 0146 m_windowsTracker = new ViewPart::WindowsTracker(this); 0147 emit windowsTrackerChanged(); 0148 } 0149 0150 if (!m_visibility) { 0151 m_visibility = new ViewPart::VisibilityManager(this); 0152 0153 connect(m_visibility, &ViewPart::VisibilityManager::isHiddenChanged, this, [&]() { 0154 if (m_visibility->isHidden()) { 0155 m_interface->deactivateApplets(); 0156 } 0157 }); 0158 0159 connect(m_visibility, &ViewPart::VisibilityManager::containsMouseChanged, 0160 this, &View::updateTransientWindowsTracking); 0161 0162 //! Deprecated because with Plasma 5.19.3 the issue does not appear. 0163 //! The issue was that when FrameExtents where zero strange behaviors were 0164 //! occuring from KWin, e.g. the panels were moving outside of screen and 0165 //! panel external shadows were positioned out of place. 0166 /*connect(m_visibility, &ViewPart::VisibilityManager::frameExtentsCleared, this, [&]() { 0167 if (behaveAsPlasmaPanel()) { 0168 //! recreate view because otherwise compositor frame extents implementation 0169 //! is triggering a crazy behavior of moving/hiding the view and freezing Latte 0170 //! in some cases. 0171 //reloadSource(); 0172 } 0173 });*/ 0174 0175 emit visibilityChanged(); 0176 } 0177 0178 if (!m_indicator) { 0179 m_indicator = new ViewPart::Indicator(this); 0180 emit indicatorChanged(); 0181 } 0182 0183 if (m_positioner) { 0184 //! immediateSyncGeometry helps avoiding binding loops from containment qml side 0185 m_positioner->immediateSyncGeometry(); 0186 } 0187 0188 connect(this->containment(), SIGNAL(statusChanged(Plasma::Types::ItemStatus)), SLOT(statusChanged(Plasma::Types::ItemStatus))); 0189 connect(this->containment(), &Plasma::Containment::showAddWidgetsInterface, this, &View::showWidgetExplorer); 0190 connect(this->containment(), &Plasma::Containment::userConfiguringChanged, this, [&]() { 0191 emit inEditModeChanged(); 0192 }); 0193 0194 connect(this->containment(), &Plasma::Containment::destroyedChanged, this, [&]() { 0195 m_inDelete = containment()->destroyed(); 0196 }); 0197 0198 if (m_corona->viewSettingsFactory()->hasOrphanSettings() 0199 && m_corona->viewSettingsFactory()->hasVisibleSettings() 0200 && m_corona->viewSettingsFactory()->lastContainment() == containment()) { 0201 //! used mostly from view recreations in order to inform config windows that view has been updated 0202 m_primaryConfigView = m_corona->viewSettingsFactory()->primaryConfigView(); 0203 m_primaryConfigView->setParentView(this, true); 0204 } 0205 0206 emit containmentActionsChanged(); 0207 }, Qt::DirectConnection); 0208 0209 if (m_corona) { 0210 connect(m_corona, &Latte::Corona::viewLocationChanged, this, &View::dockLocationChanged); 0211 } 0212 } 0213 0214 View::~View() 0215 { 0216 m_inDelete = true; 0217 0218 //! clear Layout connections 0219 m_visibleHackTimer1.stop(); 0220 m_visibleHackTimer2.stop(); 0221 for (auto &c : connectionsLayout) { 0222 disconnect(c); 0223 } 0224 0225 //! unload indicators 0226 if (m_indicator) { 0227 m_indicator->unloadIndicators(); 0228 } 0229 0230 disconnectSensitiveSignals(); 0231 disconnect(containment(), SIGNAL(statusChanged(Plasma::Types::ItemStatus)), this, SLOT(statusChanged(Plasma::Types::ItemStatus))); 0232 0233 qDebug() << "dock view deleting..."; 0234 0235 //! this disconnect does not free up connections correctly when 0236 //! latteView is deleted. A crash for this example is the following: 0237 //! switch to Alternative Session and disable compositing, 0238 //! the signal creating the crash was probably from deleted 0239 //! windows. 0240 //! this->disconnect(); 0241 0242 if (m_primaryConfigView && m_corona->inQuit()) { 0243 //! delete only when application is quitting 0244 delete m_primaryConfigView; 0245 } 0246 0247 if (m_appletConfigView) { 0248 delete m_appletConfigView; 0249 } 0250 0251 //needs to be deleted before Effects because it catches some of its signals 0252 if (m_positioner) { 0253 delete m_positioner; 0254 } 0255 0256 if (m_effects) { 0257 delete m_effects; 0258 } 0259 0260 if (m_indicator) { 0261 delete m_indicator; 0262 } 0263 0264 if (m_interface) { 0265 delete m_interface; 0266 } 0267 0268 if (m_visibility) { 0269 delete m_visibility; 0270 } 0271 0272 if (m_windowsTracker) { 0273 delete m_windowsTracker; 0274 } 0275 } 0276 0277 void View::init(Plasma::Containment *plasma_containment) 0278 { 0279 connect(this, &QQuickWindow::xChanged, this, &View::geometryChanged); 0280 connect(this, &QQuickWindow::yChanged, this, &View::geometryChanged); 0281 connect(this, &QQuickWindow::widthChanged, this, &View::geometryChanged); 0282 connect(this, &QQuickWindow::heightChanged, this, &View::geometryChanged); 0283 0284 connect(this, &QQuickWindow::xChanged, this, &View::xChanged); 0285 connect(this, &QQuickWindow::xChanged, this, &View::updateAbsoluteGeometry); 0286 connect(this, &QQuickWindow::yChanged, this, &View::yChanged); 0287 connect(this, &QQuickWindow::yChanged, this, &View::updateAbsoluteGeometry); 0288 connect(this, &QQuickWindow::widthChanged, this, &View::widthChanged); 0289 connect(this, &QQuickWindow::widthChanged, this, &View::updateAbsoluteGeometry); 0290 connect(this, &QQuickWindow::heightChanged, this, &View::heightChanged); 0291 connect(this, &QQuickWindow::heightChanged, this, &View::updateAbsoluteGeometry); 0292 0293 connect(this, &View::fontPixelSizeChanged, this, &View::editThicknessChanged); 0294 connect(this, &View::maxNormalThicknessChanged, this, &View::editThicknessChanged); 0295 0296 connect(this, &View::activitiesChanged, this, &View::applyActivitiesToWindows); 0297 connect(m_positioner, &ViewPart::Positioner::winIdChanged, this, &View::applyActivitiesToWindows); 0298 0299 connect(this, &View::alignmentChanged, this, [&](){ 0300 // inform neighbour vertical docks/panels to adjust their positioning 0301 if (m_inDelete || formFactor() == Plasma::Types::Vertical) { 0302 return; 0303 } 0304 0305 emit availableScreenRectChangedFrom(this); 0306 emit availableScreenRegionChangedFrom(this); 0307 }); 0308 0309 connect(this, &View::maxLengthChanged, this, [&]() { 0310 if (m_inDelete) { 0311 return; 0312 } 0313 0314 emit availableScreenRectChangedFrom(this); 0315 emit availableScreenRegionChangedFrom(this); 0316 }); 0317 0318 connect(this, &View::offsetChanged, this, [&]() { 0319 if (m_inDelete ) { 0320 return; 0321 } 0322 0323 emit availableScreenRectChangedFrom(this); 0324 emit availableScreenRegionChangedFrom(this); 0325 }); 0326 0327 connect(this, &View::localGeometryChanged, this, [&]() { 0328 updateAbsoluteGeometry(); 0329 }); 0330 connect(this, &View::screenEdgeMarginEnabledChanged, this, [&]() { 0331 updateAbsoluteGeometry(); 0332 }); 0333 0334 //! used in order to disconnect it when it should NOT be called because it creates crashes 0335 connect(this, &View::availableScreenRectChangedFrom, m_corona, &Latte::Corona::availableScreenRectChangedFrom); 0336 connect(this, &View::availableScreenRegionChangedFrom, m_corona, &Latte::Corona::availableScreenRegionChangedFrom); 0337 connect(m_corona, &Latte::Corona::availableScreenRectChangedFrom, this, &View::availableScreenRectChangedFromSlot); 0338 connect(m_corona, &Latte::Corona::verticalUnityViewHasFocus, this, &View::topViewAlwaysOnTop); 0339 0340 connect(this, &View::byPassWMChanged, this, &View::saveConfig); 0341 connect(this, &View::isPreferredForShortcutsChanged, this, &View::saveConfig); 0342 connect(this, &View::nameChanged, this, &View::saveConfig); 0343 connect(this, &View::onPrimaryChanged, this, &View::saveConfig); 0344 connect(this, &View::typeChanged, this, &View::saveConfig); 0345 0346 connect(this, &View::normalThicknessChanged, this, [&]() { 0347 emit availableScreenRectChangedFrom(this); 0348 }); 0349 0350 connect(m_effects, &ViewPart::Effects::innerShadowChanged, this, [&]() { 0351 emit availableScreenRectChangedFrom(this); 0352 }); 0353 connect(m_positioner, &ViewPart::Positioner::onHideWindowsForSlidingOut, this, &View::hideWindowsForSlidingOut); 0354 connect(m_positioner, &ViewPart::Positioner::screenGeometryChanged, this, &View::screenGeometryChanged); 0355 connect(m_positioner, &ViewPart::Positioner::windowSizeChanged, this, [&]() { 0356 emit availableScreenRectChangedFrom(this); 0357 }); 0358 0359 connect(m_interface, &ViewPart::ContainmentInterface::hasExpandedAppletChanged, this, &View::verticalUnityViewHasFocus); 0360 0361 //! View sends this signal in order to avoid crashes from ViewPart::Indicator when the view is recreated 0362 connect(m_corona->indicatorFactory(), &Latte::Indicator::Factory::indicatorChanged, this, [&](const QString &indicatorId) { 0363 emit indicatorPluginChanged(indicatorId); 0364 }); 0365 0366 connect(this, &View::indicatorPluginChanged, this, [&](const QString &indicatorId) { 0367 if (m_indicator && m_indicator->isCustomIndicator() && m_indicator->type() == indicatorId) { 0368 reloadSource(); 0369 } 0370 }); 0371 0372 connect(m_corona->indicatorFactory(), &Latte::Indicator::Factory::indicatorRemoved, this, &View::indicatorPluginRemoved); 0373 0374 //! Assign app interfaces in be accessible through containment graphic item 0375 QQuickItem *containmentGraphicItem = qobject_cast<QQuickItem *>(plasma_containment->property("_plasma_graphicObject").value<QObject *>()); 0376 0377 if (containmentGraphicItem) { 0378 containmentGraphicItem->setProperty("_latte_globalShortcuts_object", QVariant::fromValue(m_corona->globalShortcuts()->shortcutsTracker())); 0379 containmentGraphicItem->setProperty("_latte_layoutsManager_object", QVariant::fromValue(m_corona->layoutsManager())); 0380 containmentGraphicItem->setProperty("_latte_themeExtended_object", QVariant::fromValue(m_corona->themeExtended())); 0381 containmentGraphicItem->setProperty("_latte_universalSettings_object", QVariant::fromValue(m_corona->universalSettings())); 0382 containmentGraphicItem->setProperty("_latte_view_object", QVariant::fromValue(this)); 0383 0384 Latte::Interfaces *ifacesGraphicObject = qobject_cast<Latte::Interfaces *>(containmentGraphicItem->property("_latte_view_interfacesobject").value<QObject *>()); 0385 0386 if (ifacesGraphicObject) { 0387 ifacesGraphicObject->updateView(); 0388 setInterfacesGraphicObj(ifacesGraphicObject); 0389 } 0390 } 0391 0392 setSource(corona()->kPackage().filePath("lattedockui")); 0393 0394 //! immediateSyncGeometry helps avoiding binding loops from containment qml side 0395 m_positioner->immediateSyncGeometry(); 0396 0397 qDebug() << "SOURCE:" << source(); 0398 } 0399 0400 void View::reloadSource() 0401 { 0402 if (m_layout && containment()) { 0403 // if (settingsWindowIsShown()) { 0404 // m_configView->deleteLater(); 0405 // } 0406 0407 engine()->clearComponentCache(); 0408 m_layout->recreateView(containment(), settingsWindowIsShown()); 0409 } 0410 } 0411 0412 bool View::inDelete() const 0413 { 0414 return m_inDelete; 0415 } 0416 0417 bool View::inReadyState() const 0418 { 0419 return (m_layout != nullptr); 0420 } 0421 0422 void View::disconnectSensitiveSignals() 0423 { 0424 m_initLayoutTimer.stop(); 0425 0426 disconnect(this, &View::availableScreenRectChangedFrom, m_corona, &Latte::Corona::availableScreenRectChangedFrom); 0427 disconnect(this, &View::availableScreenRegionChangedFrom, m_corona, &Latte::Corona::availableScreenRegionChangedFrom); 0428 disconnect(m_corona, &Latte::Corona::availableScreenRectChangedFrom, this, &View::availableScreenRectChangedFromSlot); 0429 disconnect(m_corona, &Latte::Corona::verticalUnityViewHasFocus, this, &View::topViewAlwaysOnTop); 0430 0431 setLayout(nullptr); 0432 } 0433 0434 void View::availableScreenRectChangedFromSlot(View *origin) 0435 { 0436 if (m_inDelete || origin == this || !origin) { 0437 return; 0438 } 0439 0440 if (formFactor() == Plasma::Types::Vertical 0441 && origin->formFactor() == Plasma::Types::Horizontal //! accept only horizontal views 0442 && !(origin->location() == Plasma::Types::TopEdge && m_positioner->isStickedOnTopEdge()) //! ignore signals in such case 0443 && !(origin->location() == Plasma::Types::BottomEdge && m_positioner->isStickedOnBottomEdge()) //! ignore signals in such case 0444 && origin->layout() 0445 && m_layout 0446 && origin->layout()->lastUsedActivity() == m_layout->lastUsedActivity()) { 0447 //! must be in same activity 0448 m_positioner->syncGeometry(); 0449 } 0450 } 0451 0452 void View::setupWaylandIntegration() 0453 { 0454 if (m_shellSurface) 0455 return; 0456 0457 if (Latte::Corona *c = qobject_cast<Latte::Corona *>(corona())) { 0458 using namespace KWayland::Client; 0459 PlasmaShell *interface {c->waylandCoronaInterface()}; 0460 0461 if (!interface) 0462 return; 0463 0464 Surface *s{Surface::fromWindow(this)}; 0465 0466 if (!s) 0467 return; 0468 0469 m_shellSurface = interface->createSurface(s, this); 0470 qDebug() << "WAYLAND dock window surface was created..."; 0471 if (m_visibility) { 0472 m_visibility->initViewFlags(); 0473 } 0474 if (m_positioner) { 0475 m_positioner->updateWaylandId(); 0476 } 0477 } 0478 } 0479 0480 KWayland::Client::PlasmaShellSurface *View::surface() 0481 { 0482 return m_shellSurface; 0483 } 0484 0485 //! the main function which decides if this dock is at the 0486 //! correct screen 0487 void View::reconsiderScreen() 0488 { 0489 m_positioner->reconsiderScreen(); 0490 } 0491 0492 void View::duplicateView() 0493 { 0494 QString storedTmpViewFilepath = m_layout->storedView(containment()->id()); 0495 newView(storedTmpViewFilepath); 0496 } 0497 0498 void View::exportTemplate() 0499 { 0500 Latte::Settings::Dialog::ExportTemplateDialog *exportDlg = new Latte::Settings::Dialog::ExportTemplateDialog(this); 0501 exportDlg->show(); 0502 } 0503 0504 void View::newView(const QString &templateFile) 0505 { 0506 if (templateFile.isEmpty() || !m_layout) { 0507 return; 0508 } 0509 0510 Data::ViewsTable templateviews = Layouts::Storage::self()->views(templateFile); 0511 0512 if (templateviews.rowCount() <= 0) { 0513 return; 0514 } 0515 0516 Data::View nextdata = templateviews[0]; 0517 int scrId = onPrimary() ? m_corona->screenPool()->primaryScreenId() : m_positioner->currentScreenId(); 0518 0519 QList<Plasma::Types::Location> freeedges = m_layout->freeEdges(scrId); 0520 0521 if (!freeedges.contains(nextdata.edge)) { 0522 nextdata.edge = (freeedges.count() > 0 ? freeedges[0] : Plasma::Types::BottomEdge); 0523 } 0524 0525 nextdata.setState(Data::View::OriginFromViewTemplate, templateFile); 0526 0527 m_layout->newView(nextdata); 0528 } 0529 0530 void View::removeView() 0531 { 0532 if (m_layout) { 0533 QAction *removeAct = action("remove"); 0534 0535 if (removeAct) { 0536 removeAct->trigger(); 0537 } 0538 } 0539 } 0540 0541 bool View::settingsWindowIsShown() 0542 { 0543 return m_primaryConfigView && (m_primaryConfigView->parentView()==this) && m_primaryConfigView->isVisible(); 0544 } 0545 0546 void View::showSettingsWindow() 0547 { 0548 if (!settingsWindowIsShown()) { 0549 emit m_visibility->mustBeShown(); 0550 showConfigurationInterface(containment()); 0551 applyActivitiesToWindows(); 0552 } 0553 } 0554 0555 QQuickView *View::configView() 0556 { 0557 return m_primaryConfigView.data(); 0558 } 0559 0560 void View::showConfigurationInterface(Plasma::Applet *applet) 0561 { 0562 if (!applet || !applet->containment()) 0563 return; 0564 0565 Plasma::Containment *c = qobject_cast<Plasma::Containment *>(applet); 0566 0567 if (m_primaryConfigView && c && c->isContainment() && c == this->containment()) { 0568 if (m_primaryConfigView->isVisible()) { 0569 m_primaryConfigView->hideConfigWindow(); 0570 } else { 0571 m_primaryConfigView->showConfigWindow(); 0572 applyActivitiesToWindows(); 0573 } 0574 0575 return; 0576 } else if (m_appletConfigView) { 0577 if (m_appletConfigView->applet() == applet) { 0578 m_appletConfigView->show(); 0579 0580 if (KWindowSystem::isPlatformX11()) { 0581 m_appletConfigView->requestActivate(); 0582 } 0583 return; 0584 } else { 0585 m_appletConfigView->hide(); 0586 } 0587 } 0588 0589 bool delayConfigView = false; 0590 0591 if (c && containment() && c->isContainment() && c->id() == containment()->id()) { 0592 m_primaryConfigView = m_corona->viewSettingsFactory()->primaryConfigView(this); 0593 applyActivitiesToWindows(); 0594 } else { 0595 m_appletConfigView = new PlasmaQuick::ConfigView(applet); 0596 m_appletConfigView.data()->init(); 0597 0598 //! center applet config window 0599 m_appletConfigView->setScreen(screen()); 0600 QRect scrgeometry = screenGeometry(); 0601 QPoint position{scrgeometry.center().x() - m_appletConfigView->width() / 2, scrgeometry.center().y() - m_appletConfigView->height() / 2 }; 0602 //!under wayland probably needs another workaround 0603 m_appletConfigView->setPosition(position); 0604 0605 m_appletConfigView->show(); 0606 } 0607 } 0608 0609 void View::showWidgetExplorer(const QPointF &point) 0610 { 0611 auto widgetExplorerView = m_corona->viewSettingsFactory()->widgetExplorerView(this); 0612 0613 if (!widgetExplorerView->isVisible()) { 0614 widgetExplorerView->showAfter(250); 0615 } 0616 } 0617 0618 QRect View::localGeometry() const 0619 { 0620 return m_localGeometry; 0621 } 0622 0623 void View::setLocalGeometry(const QRect &geometry) 0624 { 0625 if (m_localGeometry == geometry) { 0626 return; 0627 } 0628 0629 m_localGeometry = geometry; 0630 emit localGeometryChanged(); 0631 } 0632 0633 0634 QString View::name() const 0635 { 0636 return m_name; 0637 } 0638 0639 void View::setName(const QString &newname) 0640 { 0641 if (m_name == newname) { 0642 return; 0643 } 0644 0645 m_name = newname; 0646 emit nameChanged(); 0647 } 0648 0649 QString View::validTitle() const 0650 { 0651 if (!containment()) { 0652 return QString(); 0653 } 0654 0655 return QString("#view#" + QString::number(containment()->id())); 0656 } 0657 0658 void View::updateAbsoluteGeometry(bool bypassChecks) 0659 { 0660 //! there was a -1 in height and width here. The reason of this 0661 //! if I remember correctly was related to multi-screen but I cant 0662 //! remember exactly the reason, something related to right edge in 0663 //! multi screen environment. BUT this was breaking the entire AlwaysVisible 0664 //! experience with struts. Removing them in order to restore correct 0665 //! behavior and keeping this comment in order to check for 0666 //! multi-screen breakage 0667 QRect absGeometry = m_localGeometry; 0668 absGeometry.moveLeft(x() + m_localGeometry.x()); 0669 absGeometry.moveTop(y() + m_localGeometry.y()); 0670 0671 if (behaveAsPlasmaPanel()) { 0672 int currentScreenEdgeMargin = m_screenEdgeMarginEnabled ? qMax(0, m_screenEdgeMargin) : 0; 0673 0674 if (location() == Plasma::Types::BottomEdge) { 0675 absGeometry.moveTop(screenGeometry().bottom() - currentScreenEdgeMargin - m_normalThickness); 0676 } else if (location() == Plasma::Types::TopEdge) { 0677 absGeometry.moveTop(screenGeometry().top() + currentScreenEdgeMargin); 0678 } else if (location() == Plasma::Types::LeftEdge) { 0679 absGeometry.moveLeft(screenGeometry().left() + currentScreenEdgeMargin); 0680 } else if (location() == Plasma::Types::RightEdge) { 0681 absGeometry.moveLeft(screenGeometry().right() - currentScreenEdgeMargin - m_normalThickness); 0682 } 0683 } 0684 0685 if (KWindowSystem::isPlatformX11() && devicePixelRatio() != 1.0) { 0686 //!Fix for X11 Global Scale, I dont think this could be pixel perfect accurate 0687 auto factor = devicePixelRatio(); 0688 absGeometry = QRect(qRound(absGeometry.x() * factor), 0689 qRound(absGeometry.y() * factor), 0690 qRound(absGeometry.width() * factor), 0691 qRound(absGeometry.height() * factor)); 0692 } 0693 0694 if (m_absoluteGeometry == absGeometry && !bypassChecks) { 0695 return; 0696 } 0697 0698 if (m_absoluteGeometry != absGeometry) { 0699 m_absoluteGeometry = absGeometry; 0700 emit absoluteGeometryChanged(m_absoluteGeometry); 0701 } 0702 0703 if ((m_absoluteGeometry != absGeometry) || bypassChecks) { 0704 //! inform others such as neighbour vertical views that new geometries are applied 0705 //! main use of BYPASSCKECKS is from Positioner when the view changes screens 0706 emit availableScreenRectChangedFrom(this); 0707 emit availableScreenRegionChangedFrom(this); 0708 } 0709 } 0710 0711 void View::statusChanged(Plasma::Types::ItemStatus status) 0712 { 0713 if (!containment()) { 0714 return; 0715 } 0716 0717 //! Fix for #443236, following setFlags(...) need to be added at all three cases 0718 //! but initViewFlags() should be called afterwards because setFlags(...) breaks 0719 //! the Dock window default behavior under x11 0720 if (status == Plasma::Types::NeedsAttentionStatus || status == Plasma::Types::RequiresAttentionStatus) { 0721 m_visibility->addBlockHidingEvent(BLOCKHIDINGNEEDSATTENTIONTYPE); 0722 setFlags(flags() | Qt::WindowDoesNotAcceptFocus); 0723 m_visibility->initViewFlags(); 0724 if (m_shellSurface) { 0725 m_shellSurface->setPanelTakesFocus(false); 0726 } 0727 } else if (status == Plasma::Types::AcceptingInputStatus) { 0728 m_visibility->removeBlockHidingEvent(BLOCKHIDINGNEEDSATTENTIONTYPE); 0729 setFlags(flags() & ~Qt::WindowDoesNotAcceptFocus); 0730 m_visibility->initViewFlags(); 0731 if (KWindowSystem::isPlatformX11()) { 0732 KWindowSystem::forceActiveWindow(winId()); 0733 } 0734 if (m_shellSurface) { 0735 m_shellSurface->setPanelTakesFocus(true); 0736 } 0737 } else { 0738 updateTransientWindowsTracking(); 0739 m_visibility->removeBlockHidingEvent(BLOCKHIDINGNEEDSATTENTIONTYPE); 0740 setFlags(flags() | Qt::WindowDoesNotAcceptFocus); 0741 m_visibility->initViewFlags(); 0742 if (m_shellSurface) { 0743 m_shellSurface->setPanelTakesFocus(false); 0744 } 0745 } 0746 } 0747 0748 void View::addTransientWindow(QWindow *window) 0749 { 0750 if (!m_transientWindows.contains(window) && !window->flags().testFlag(Qt::ToolTip) && !window->title().startsWith("#debugwindow#")) { 0751 m_transientWindows.append(window); 0752 0753 QString winPtrStr = "0x" + QString::number((qulonglong)window,16); 0754 m_visibility->addBlockHidingEvent(winPtrStr); 0755 0756 if (m_visibility->hasBlockHidingEvent(Latte::GlobalShortcuts::SHORTCUTBLOCKHIDINGTYPE)) { 0757 m_visibility->removeBlockHidingEvent(Latte::GlobalShortcuts::SHORTCUTBLOCKHIDINGTYPE); 0758 } 0759 0760 connect(window, &QWindow::visibleChanged, this, &View::removeTransientWindow); 0761 } 0762 } 0763 0764 void View::removeTransientWindow(const bool &visible) 0765 { 0766 QWindow *window = static_cast<QWindow *>(QObject::sender()); 0767 0768 if (window && !visible) { 0769 QString winPtrStr = "0x" + QString::number((qulonglong)window,16); 0770 m_visibility->removeBlockHidingEvent(winPtrStr); 0771 disconnect(window, &QWindow::visibleChanged, this, &View::removeTransientWindow); 0772 m_transientWindows.removeAll(window); 0773 0774 if (m_visibility->hasBlockHidingEvent(Latte::GlobalShortcuts::SHORTCUTBLOCKHIDINGTYPE)) { 0775 m_visibility->removeBlockHidingEvent(Latte::GlobalShortcuts::SHORTCUTBLOCKHIDINGTYPE); 0776 } 0777 0778 updateTransientWindowsTracking(); 0779 } 0780 } 0781 0782 void View::updateTransientWindowsTracking() 0783 { 0784 for(QWindow *window: qApp->topLevelWindows()) { 0785 if (window->transientParent() == this && window->isVisible()){ 0786 addTransientWindow(window); 0787 break; 0788 } 0789 } 0790 } 0791 0792 Types::ViewType View::type() const 0793 { 0794 return m_type; 0795 } 0796 0797 void View::setType(Types::ViewType type) 0798 { 0799 if (m_type == type) { 0800 return; 0801 } 0802 0803 m_type = type; 0804 emit typeChanged(); 0805 } 0806 0807 bool View::alternativesIsShown() const 0808 { 0809 return m_alternativesIsShown; 0810 } 0811 0812 void View::setAlternativesIsShown(bool show) 0813 { 0814 if (m_alternativesIsShown == show) { 0815 return; 0816 } 0817 0818 m_alternativesIsShown = show; 0819 0820 emit alternativesIsShownChanged(); 0821 } 0822 0823 bool View::containsDrag() const 0824 { 0825 return m_containsDrag; 0826 } 0827 0828 void View::setContainsDrag(bool contains) 0829 { 0830 if (m_containsDrag == contains) { 0831 return; 0832 } 0833 0834 m_containsDrag = contains; 0835 0836 0837 if (m_containsDrag) { 0838 m_visibility->addBlockHidingEvent(BLOCKHIDINGDRAGTYPE); 0839 } else { 0840 m_visibility->removeBlockHidingEvent(BLOCKHIDINGDRAGTYPE); 0841 } 0842 0843 emit containsDragChanged(); 0844 } 0845 0846 bool View::containsMouse() const 0847 { 0848 return m_containsMouse; 0849 } 0850 0851 int View::normalThickness() const 0852 { 0853 return m_normalThickness; 0854 } 0855 0856 void View::setNormalThickness(int thickness) 0857 { 0858 if (m_normalThickness == thickness) { 0859 return; 0860 } 0861 0862 m_normalThickness = thickness; 0863 emit normalThicknessChanged(); 0864 } 0865 0866 int View::maxNormalThickness() const 0867 { 0868 return m_maxNormalThickness; 0869 } 0870 0871 void View::setMaxNormalThickness(int thickness) 0872 { 0873 if (m_maxNormalThickness == thickness) { 0874 return; 0875 } 0876 0877 m_maxNormalThickness = thickness; 0878 emit maxNormalThicknessChanged(); 0879 } 0880 0881 int View::headThicknessGap() const 0882 { 0883 return m_headThicknessGap; 0884 } 0885 0886 void View::setHeadThicknessGap(int thickness) 0887 { 0888 if (m_headThicknessGap == thickness) { 0889 return; 0890 } 0891 0892 m_headThicknessGap = thickness; 0893 emit headThicknessGapChanged(); 0894 } 0895 0896 bool View::byPassWM() const 0897 { 0898 return m_byPassWM; 0899 } 0900 0901 void View::setByPassWM(bool bypass) 0902 { 0903 if (m_byPassWM == bypass) { 0904 return; 0905 } 0906 0907 m_byPassWM = bypass; 0908 emit byPassWMChanged(); 0909 } 0910 0911 bool View::behaveAsPlasmaPanel() const 0912 { 0913 return m_behaveAsPlasmaPanel; 0914 } 0915 0916 void View::setBehaveAsPlasmaPanel(bool behavior) 0917 { 0918 if (m_behaveAsPlasmaPanel == behavior) { 0919 return; 0920 } 0921 0922 m_behaveAsPlasmaPanel = behavior; 0923 0924 emit behaveAsPlasmaPanelChanged(); 0925 } 0926 0927 bool View::inEditMode() const 0928 { 0929 return containment() && containment()->isUserConfiguring(); 0930 } 0931 0932 bool View::isFloatingPanel() const 0933 { 0934 return m_behaveAsPlasmaPanel && m_screenEdgeMarginEnabled && (m_screenEdgeMargin>0); 0935 } 0936 0937 bool View::isPreferredForShortcuts() const 0938 { 0939 return m_isPreferredForShortcuts; 0940 } 0941 0942 void View::setIsPreferredForShortcuts(bool preferred) 0943 { 0944 if (m_isPreferredForShortcuts == preferred) { 0945 return; 0946 } 0947 0948 m_isPreferredForShortcuts = preferred; 0949 0950 emit isPreferredForShortcutsChanged(); 0951 0952 if (m_isPreferredForShortcuts && m_layout) { 0953 emit m_layout->preferredViewForShortcutsChanged(this); 0954 } 0955 } 0956 0957 bool View::inSettingsAdvancedMode() const 0958 { 0959 return m_primaryConfigView && m_corona->universalSettings()->inAdvancedModeForEditSettings(); 0960 } 0961 0962 bool View::isTouchingBottomViewAndIsBusy() const 0963 { 0964 return m_isTouchingBottomViewAndIsBusy; 0965 } 0966 0967 void View::setIsTouchingBottomViewAndIsBusy(bool touchAndBusy) 0968 { 0969 if (m_isTouchingBottomViewAndIsBusy == touchAndBusy) { 0970 return; 0971 } 0972 0973 m_isTouchingBottomViewAndIsBusy = touchAndBusy; 0974 0975 emit isTouchingBottomViewAndIsBusyChanged(); 0976 } 0977 0978 bool View::isTouchingTopViewAndIsBusy() const 0979 { 0980 return m_isTouchingTopViewAndIsBusy; 0981 } 0982 0983 void View::setIsTouchingTopViewAndIsBusy(bool touchAndBusy) 0984 { 0985 if (m_isTouchingTopViewAndIsBusy == touchAndBusy) { 0986 return; 0987 } 0988 0989 m_isTouchingTopViewAndIsBusy = touchAndBusy; 0990 emit isTouchingTopViewAndIsBusyChanged(); 0991 } 0992 0993 void View::preferredViewForShortcutsChangedSlot(Latte::View *view) 0994 { 0995 if (view != this) { 0996 setIsPreferredForShortcuts(false); 0997 } 0998 } 0999 1000 bool View::onPrimary() const 1001 { 1002 return m_onPrimary; 1003 } 1004 1005 void View::setOnPrimary(bool flag) 1006 { 1007 if (m_onPrimary == flag) { 1008 return; 1009 } 1010 1011 m_onPrimary = flag; 1012 emit onPrimaryChanged(); 1013 } 1014 1015 int View::groupId() const 1016 { 1017 if (!containment()) { 1018 return -1; 1019 } 1020 1021 return containment()->id(); 1022 } 1023 1024 float View::maxLength() const 1025 { 1026 return m_maxLength; 1027 } 1028 1029 void View::setMaxLength(float length) 1030 { 1031 if (m_maxLength == length) { 1032 return; 1033 } 1034 1035 m_maxLength = length; 1036 emit maxLengthChanged(); 1037 } 1038 1039 int View::editThickness() const 1040 { 1041 int smallspacing = 4; 1042 int ruler_height{m_fontPixelSize}; 1043 int header_height{m_fontPixelSize + 2*smallspacing}; 1044 1045 int edgeThickness = behaveAsPlasmaPanel() && screenEdgeMarginEnabled() ? m_screenEdgeMargin : 0; 1046 1047 return edgeThickness + m_maxNormalThickness + ruler_height + header_height + 6*smallspacing; 1048 } 1049 1050 int View::maxThickness() const 1051 { 1052 return m_maxThickness; 1053 } 1054 1055 void View::setMaxThickness(int thickness) 1056 { 1057 if (m_maxThickness == thickness) 1058 return; 1059 1060 m_maxThickness = thickness; 1061 emit maxThicknessChanged(); 1062 } 1063 1064 int View::alignment() const 1065 { 1066 return m_alignment; 1067 } 1068 1069 void View::setAlignment(int alignment) 1070 { 1071 Types::Alignment align = static_cast<Types::Alignment>(alignment); 1072 1073 if (m_alignment == alignment) { 1074 return; 1075 } 1076 1077 m_alignment = align; 1078 emit alignmentChanged(); 1079 } 1080 1081 QRect View::absoluteGeometry() const 1082 { 1083 return m_absoluteGeometry; 1084 } 1085 1086 QRect View::screenGeometry() const 1087 { 1088 if (this->screen()) { 1089 QRect geom = this->screen()->geometry(); 1090 return geom; 1091 } 1092 1093 return QRect(); 1094 } 1095 1096 float View::offset() const 1097 { 1098 return m_offset; 1099 } 1100 1101 void View::setOffset(float offset) 1102 { 1103 if (m_offset == offset) { 1104 return; 1105 } 1106 1107 m_offset = offset; 1108 emit offsetChanged(); 1109 } 1110 1111 bool View::screenEdgeMarginEnabled() const 1112 { 1113 return m_screenEdgeMarginEnabled; 1114 } 1115 1116 void View::setScreenEdgeMarginEnabled(bool enabled) 1117 { 1118 if (m_screenEdgeMarginEnabled == enabled) { 1119 return; 1120 } 1121 1122 m_screenEdgeMarginEnabled = enabled; 1123 emit screenEdgeMarginEnabledChanged(); 1124 } 1125 1126 int View::screenEdgeMargin() const 1127 { 1128 return m_screenEdgeMargin; 1129 } 1130 1131 void View::setScreenEdgeMargin(int margin) 1132 { 1133 if (m_screenEdgeMargin == margin) { 1134 return; 1135 } 1136 1137 1138 1139 m_screenEdgeMargin = margin; 1140 emit screenEdgeMarginChanged(); 1141 } 1142 1143 int View::fontPixelSize() const 1144 { 1145 return m_fontPixelSize; 1146 } 1147 1148 void View::setFontPixelSize(int size) 1149 { 1150 if (m_fontPixelSize == size) { 1151 return; 1152 } 1153 1154 m_fontPixelSize = size; 1155 1156 emit fontPixelSizeChanged(); 1157 } 1158 1159 bool View::isOnAllActivities() const 1160 { 1161 return m_activities.isEmpty() || m_activities[0] == Data::Layout::ALLACTIVITIESID; 1162 } 1163 1164 bool View::isOnActivity(const QString &activity) const 1165 { 1166 return isOnAllActivities() || m_activities.contains(activity); 1167 } 1168 1169 QStringList View::activities() const 1170 { 1171 QStringList running; 1172 1173 QStringList runningAll = m_corona->activitiesConsumer()->runningActivities(); 1174 1175 for(int i=0; i<m_activities.count(); ++i) { 1176 if (runningAll.contains(m_activities[i])) { 1177 running << m_activities[i]; 1178 } 1179 } 1180 1181 return running; 1182 } 1183 1184 void View::setActivities(const QStringList &ids) 1185 { 1186 if (m_activities == ids) { 1187 return; 1188 } 1189 1190 m_activities = ids; 1191 emit activitiesChanged(); 1192 } 1193 1194 void View::applyActivitiesToWindows() 1195 { 1196 if (m_visibility && m_positioner && m_layout) { 1197 QStringList runningActivities = activities(); 1198 1199 m_positioner->setWindowOnActivities(m_positioner->trackedWindowId(), runningActivities); 1200 1201 //! config windows 1202 if (m_primaryConfigView) { 1203 m_primaryConfigView->setOnActivities(runningActivities); 1204 } 1205 1206 if (m_appletConfigView) { 1207 Latte::WindowSystem::WindowId appletconfigviewid; 1208 1209 if (KWindowSystem::isPlatformX11()) { 1210 appletconfigviewid = m_appletConfigView->winId(); 1211 } else { 1212 appletconfigviewid = m_corona->wm()->winIdFor("latte-dock", m_appletConfigView->title()); 1213 } 1214 1215 m_positioner->setWindowOnActivities(appletconfigviewid, runningActivities); 1216 } 1217 1218 //! hidden windows 1219 if (m_visibility->supportsKWinEdges()) { 1220 m_visibility->applyActivitiesToHiddenWindows(runningActivities); 1221 } 1222 } 1223 } 1224 1225 void View::showHiddenViewFromActivityStopping() 1226 { 1227 if (m_layout && m_visibility && !inDelete() && !isVisible() && !m_visibility->isHidden()) { 1228 show(); 1229 1230 if (m_effects) { 1231 m_effects->updateEnabledBorders(); 1232 } 1233 1234 //qDebug() << "View:: Enforce reshow from timer 1..."; 1235 emit forcedShown(); 1236 } else if (m_layout && isVisible()) { 1237 m_inDelete = false; 1238 //qDebug() << "View:: No needed reshow from timer 1..."; 1239 } 1240 } 1241 1242 Layout::GenericLayout *View::layout() const 1243 { 1244 return m_layout; 1245 } 1246 1247 void View::setLayout(Layout::GenericLayout *layout) 1248 { 1249 if (m_layout == layout) { 1250 return; 1251 } 1252 1253 // clear mode 1254 for (auto &c : connectionsLayout) { 1255 disconnect(c); 1256 } 1257 1258 m_layout = layout; 1259 1260 if (m_layout) { 1261 connectionsLayout << connect(containment(), &Plasma::Applet::destroyedChanged, m_layout, &Layout::GenericLayout::destroyedChanged); 1262 connectionsLayout << connect(containment(), &Plasma::Applet::locationChanged, m_corona, &Latte::Corona::viewLocationChanged); 1263 connectionsLayout << connect(containment(), &Plasma::Containment::appletAlternativesRequested, m_corona, &Latte::Corona::showAlternativesForApplet, Qt::QueuedConnection); 1264 1265 if (m_corona->layoutsManager()->memoryUsage() == MemoryUsage::MultipleLayouts) { 1266 connectionsLayout << connect(containment(), &Plasma::Containment::appletCreated, m_layout, &Layout::GenericLayout::appletCreated); 1267 } 1268 1269 connectionsLayout << connect(m_positioner, &Latte::ViewPart::Positioner::edgeChanged, m_layout, &Layout::GenericLayout::viewEdgeChanged); 1270 connectionsLayout << connect(m_layout, &Layout::GenericLayout::popUpMarginChanged, m_effects, &Latte::ViewPart::Effects::popUpMarginChanged); 1271 1272 //! Sometimes the activity isnt completely ready, by adding a delay 1273 //! we try to catch up 1274 m_initLayoutTimer.setInterval(100); 1275 m_initLayoutTimer.setSingleShot(true); 1276 connectionsLayout << connect(&m_initLayoutTimer, &QTimer::timeout, this, [&]() { 1277 if (m_layout && m_visibility) { 1278 setActivities(m_layout->appliedActivities()); 1279 qDebug() << "DOCK VIEW FROM LAYOUT ::: " << m_layout->name() << " - activities: " << m_activities; 1280 } 1281 }); 1282 m_initLayoutTimer.start(); 1283 1284 connectionsLayout << connect(m_layout, &Layout::GenericLayout::preferredViewForShortcutsChanged, this, &View::preferredViewForShortcutsChangedSlot); 1285 1286 Latte::Corona *latteCorona = qobject_cast<Latte::Corona *>(this->corona()); 1287 1288 connectionsLayout << connect(latteCorona->activitiesConsumer(), &KActivities::Consumer::currentActivityChanged, this, [&]() { 1289 if (m_layout && m_visibility) { 1290 setActivities(m_layout->appliedActivities()); 1291 //! update activities in case KWin did its magic and assigned windows to faulty activities 1292 applyActivitiesToWindows(); 1293 showHiddenViewFromActivityStopping(); 1294 qDebug() << "DOCK VIEW FROM LAYOUT (currentActivityChanged) ::: " << m_layout->name() << " - activities: " << m_activities; 1295 } 1296 }); 1297 1298 if (latteCorona->layoutsManager()->memoryUsage() == MemoryUsage::MultipleLayouts) { 1299 connectionsLayout << connect(latteCorona->activitiesConsumer(), &KActivities::Consumer::runningActivitiesChanged, this, [&]() { 1300 if (m_layout && m_visibility) { 1301 setActivities(m_layout->appliedActivities()); 1302 qDebug() << "DOCK VIEW FROM LAYOUT (runningActivitiesChanged) ::: " << m_layout->name() 1303 << " - activities: " << m_activities; 1304 } 1305 }); 1306 1307 connectionsLayout << connect(m_layout, &Layout::GenericLayout::activitiesChanged, this, [&]() { 1308 if (m_layout) { 1309 setActivities(m_layout->appliedActivities()); 1310 } 1311 }); 1312 1313 connectionsLayout << connect(latteCorona->layoutsManager()->synchronizer(), &Layouts::Synchronizer::layoutsChanged, this, [&]() { 1314 if (m_layout) { 1315 setActivities(m_layout->appliedActivities()); 1316 } 1317 }); 1318 1319 //! BEGIN OF KWIN HACK 1320 //! IMPORTANT ::: Fixing KWin Faulty Behavior that KWin hides ALL Views when an Activity stops 1321 //! with no reason!! 1322 1323 m_visibleHackTimer1.setInterval(400); 1324 m_visibleHackTimer2.setInterval(2500); 1325 m_visibleHackTimer1.setSingleShot(true); 1326 m_visibleHackTimer2.setSingleShot(true); 1327 1328 connectionsLayout << connect(this, &QWindow::visibleChanged, this, [&]() { 1329 if (m_layout && !inDelete() && !isVisible() && !m_positioner->inLayoutUnloading()) { 1330 m_visibleHackTimer1.start(); 1331 m_visibleHackTimer2.start(); 1332 } 1333 }); 1334 1335 connectionsLayout << connect(&m_visibleHackTimer1, &QTimer::timeout, this, [&]() { 1336 applyActivitiesToWindows(); 1337 showHiddenViewFromActivityStopping(); 1338 emit activitiesChanged(); 1339 }); 1340 1341 connectionsLayout << connect(&m_visibleHackTimer2, &QTimer::timeout, this, [&]() { 1342 applyActivitiesToWindows(); 1343 showHiddenViewFromActivityStopping(); 1344 emit activitiesChanged(); 1345 }); 1346 1347 //! END OF KWIN HACK 1348 } 1349 1350 emit layoutChanged(); 1351 } else { 1352 m_activities.clear(); 1353 } 1354 } 1355 1356 void View::hideWindowsForSlidingOut() 1357 { 1358 if (m_primaryConfigView) { 1359 m_primaryConfigView->hideConfigWindow(); 1360 } 1361 } 1362 1363 //!check if the plasmoid with _name_ exists in the midedata 1364 bool View::mimeContainsPlasmoid(QMimeData *mimeData, QString name) 1365 { 1366 if (!mimeData) { 1367 return false; 1368 } 1369 1370 if (mimeData->hasFormat(QStringLiteral("text/x-plasmoidservicename"))) { 1371 QString data = mimeData->data(QStringLiteral("text/x-plasmoidservicename")); 1372 const QStringList appletNames = data.split('\n', QString::SkipEmptyParts); 1373 1374 for (const QString &appletName : appletNames) { 1375 if (appletName == name) 1376 return true; 1377 } 1378 } 1379 1380 return false; 1381 } 1382 1383 Latte::Data::View View::data() const 1384 { 1385 Latte::Data::View vdata; 1386 vdata.id = QString::number(containment()->id()); 1387 vdata.name = name(); 1388 vdata.isActive = true; 1389 vdata.onPrimary = onPrimary(); 1390 1391 vdata.screen = containment()->screen(); 1392 if (!Layouts::Storage::isValid(vdata.screen)) { 1393 vdata.screen = containment()->lastScreen(); 1394 } 1395 1396 vdata.screensGroup = screensGroup(); 1397 1398 //!screen edge margin can be more accurate in the config file 1399 vdata.screenEdgeMargin = m_screenEdgeMargin > 0 ? m_screenEdgeMargin : containment()->config().group("General").readEntry("screenEdgeMargin", (int)-1); 1400 1401 vdata.edge = location(); 1402 vdata.maxLength = m_maxLength * 100; 1403 vdata.alignment = m_alignment; 1404 vdata.subcontainments = Layouts::Storage::self()->subcontainments(layout(), containment()); 1405 1406 vdata.setState(Latte::Data::View::IsCreated); 1407 return vdata; 1408 } 1409 1410 QQuickItem *View::colorizer() const 1411 { 1412 return m_colorizer; 1413 } 1414 1415 void View::setColorizer(QQuickItem *colorizer) 1416 { 1417 if (m_colorizer == colorizer) { 1418 return; 1419 } 1420 1421 m_colorizer = colorizer; 1422 emit colorizerChanged(); 1423 } 1424 1425 QQuickItem *View::metrics() const 1426 { 1427 return m_metrics; 1428 } 1429 1430 void View::setMetrics(QQuickItem *metrics) 1431 { 1432 if (m_metrics == metrics) { 1433 return; 1434 } 1435 1436 m_metrics = metrics; 1437 emit metricsChanged(); 1438 } 1439 1440 ViewPart::Effects *View::effects() const 1441 { 1442 return m_effects; 1443 } 1444 1445 ViewPart::Indicator *View::indicator() const 1446 { 1447 return m_indicator; 1448 } 1449 1450 ViewPart::ContainmentInterface *View::extendedInterface() const 1451 { 1452 return m_interface; 1453 } 1454 1455 ViewPart::Parabolic *View::parabolic() const 1456 { 1457 return m_parabolic; 1458 } 1459 1460 ViewPart::Positioner *View::positioner() const 1461 { 1462 return m_positioner; 1463 } 1464 1465 ViewPart::EventsSink *View::sink() const 1466 { 1467 return m_sink; 1468 } 1469 1470 ViewPart::VisibilityManager *View::visibility() const 1471 { 1472 return m_visibility; 1473 } 1474 1475 ViewPart::WindowsTracker *View::windowsTracker() const 1476 { 1477 return m_windowsTracker; 1478 } 1479 1480 Latte::Interfaces *View::interfacesGraphicObj() const 1481 { 1482 return m_interfacesGraphicObj; 1483 } 1484 1485 void View::setInterfacesGraphicObj(Latte::Interfaces *ifaces) 1486 { 1487 if (m_interfacesGraphicObj == ifaces) { 1488 return; 1489 } 1490 1491 m_interfacesGraphicObj = ifaces; 1492 1493 if (containment()) { 1494 QQuickItem *containmentGraphicItem = qobject_cast<QQuickItem *>(containment()->property("_plasma_graphicObject").value<QObject *>()); 1495 1496 if (containmentGraphicItem) { 1497 containmentGraphicItem->setProperty("_latte_view_interfacesobject", QVariant::fromValue(m_interfacesGraphicObj)); 1498 } 1499 } 1500 1501 emit interfacesGraphicObjChanged(); 1502 } 1503 1504 bool View::event(QEvent *e) 1505 { 1506 QEvent *sunkevent = e; 1507 1508 if (!m_inDelete) { 1509 emit eventTriggered(e); 1510 1511 bool sinkableevent{false}; 1512 1513 switch (e->type()) { 1514 case QEvent::Enter: 1515 m_containsMouse = true; 1516 break; 1517 1518 case QEvent::Leave: 1519 m_containsMouse = false; 1520 setContainsDrag(false); 1521 sinkableevent = true; 1522 break; 1523 1524 case QEvent::DragEnter: 1525 setContainsDrag(true); 1526 sinkableevent = true; 1527 break; 1528 1529 case QEvent::DragLeave: 1530 setContainsDrag(false); 1531 break; 1532 1533 case QEvent::DragMove: 1534 sinkableevent = true; 1535 break; 1536 1537 case QEvent::Drop: 1538 setContainsDrag(false); 1539 sinkableevent = true; 1540 break; 1541 1542 case QEvent::MouseMove: 1543 sinkableevent = true; 1544 break; 1545 1546 case QEvent::MouseButtonPress: 1547 if (auto me = dynamic_cast<QMouseEvent *>(e)) { 1548 emit mousePressed(me->pos(), me->button()); 1549 sinkableevent = true; 1550 verticalUnityViewHasFocus(); 1551 } 1552 break; 1553 1554 case QEvent::MouseButtonRelease: 1555 if (auto me = dynamic_cast<QMouseEvent *>(e)) { 1556 emit mouseReleased(me->pos(), me->button()); 1557 sinkableevent = true; 1558 } 1559 break; 1560 1561 case QEvent::PlatformSurface: 1562 if (auto pe = dynamic_cast<QPlatformSurfaceEvent *>(e)) { 1563 switch (pe->surfaceEventType()) { 1564 case QPlatformSurfaceEvent::SurfaceCreated: 1565 setupWaylandIntegration(); 1566 1567 if (m_shellSurface) { 1568 //! immediateSyncGeometry helps avoiding binding loops from containment qml side 1569 m_positioner->immediateSyncGeometry(); 1570 m_effects->updateShadows(); 1571 } 1572 1573 break; 1574 1575 case QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed: 1576 if (m_shellSurface) { 1577 delete m_shellSurface; 1578 m_shellSurface = nullptr; 1579 qDebug() << "WAYLAND dock window surface was deleted..."; 1580 m_effects->clearShadows(); 1581 } 1582 1583 break; 1584 } 1585 } 1586 1587 break; 1588 1589 case QEvent::Show: 1590 if (m_visibility) { 1591 m_visibility->initViewFlags(); 1592 } 1593 break; 1594 1595 case QEvent::Wheel: 1596 if (auto we = dynamic_cast<QWheelEvent *>(e)) { 1597 QPoint pos = we->position().toPoint(); 1598 emit wheelScrolled(pos, we->angleDelta(), we->buttons()); 1599 sinkableevent = true; 1600 } 1601 break; 1602 default: 1603 break; 1604 } 1605 1606 if (sinkableevent && m_sink->isActive()) { 1607 sunkevent = m_sink->onEvent(e); 1608 } 1609 } 1610 1611 return ContainmentView::event(sunkevent); 1612 } 1613 1614 void View::releaseConfigView() 1615 { 1616 m_primaryConfigView = nullptr; 1617 } 1618 1619 //! release grab and restore mouse state 1620 void View::unblockMouse(int x, int y) 1621 { 1622 setMouseGrabEnabled(false); 1623 1624 m_releaseGrab_x = x; 1625 m_releaseGrab_y = y; 1626 m_releaseGrabTimer.start(); 1627 } 1628 1629 void View::releaseGrab() 1630 { 1631 //! ungrab mouse 1632 if (mouseGrabberItem()) { 1633 mouseGrabberItem()->ungrabMouse(); 1634 } 1635 1636 //! properly release grabbed mouse in order to inform all views 1637 setMouseGrabEnabled(true); 1638 setMouseGrabEnabled(false); 1639 1640 //! Send a fake QEvent::Leave to inform applets for mouse leaving the view 1641 QHoverEvent e(QEvent::Leave, QPoint(-5,-5), QPoint(m_releaseGrab_x, m_releaseGrab_y)); 1642 QCoreApplication::instance()->sendEvent(this, &e); 1643 } 1644 1645 QAction *View::action(const QString &name) 1646 { 1647 if (!containment()) { 1648 return nullptr; 1649 } 1650 1651 return this->containment()->actions()->action(name); 1652 } 1653 1654 QVariantList View::containmentActions() const 1655 { 1656 QVariantList actions; 1657 1658 if (!containment()) { 1659 return actions; 1660 } 1661 1662 const QString trigger = "RightButton;NoModifier"; 1663 Plasma::ContainmentActions *plugin = this->containment()->containmentActions().value(trigger); 1664 1665 if (!plugin) { 1666 return actions; 1667 } 1668 1669 if (plugin->containment() != this->containment()) { 1670 plugin->setContainment(this->containment()); 1671 // now configure it 1672 KConfigGroup cfg(this->containment()->corona()->config(), "ActionPlugins"); 1673 cfg = KConfigGroup(&cfg, QString::number(this->containment()->containmentType())); 1674 KConfigGroup pluginConfig = KConfigGroup(&cfg, trigger); 1675 plugin->restore(pluginConfig); 1676 } 1677 1678 for (QAction *ac : plugin->contextualActions()) { 1679 actions << QVariant::fromValue<QAction *>(ac); 1680 } 1681 1682 return actions; 1683 } 1684 1685 bool View::isHighestPriorityView() { 1686 if (m_layout) { 1687 return this == m_layout->highestPriorityView(); 1688 } 1689 1690 return false; 1691 } 1692 1693 //! BEGIN: WORKAROUND order to force top panels always on top and above left/right panels 1694 void View::topViewAlwaysOnTop() 1695 { 1696 if (!m_visibility) { 1697 return; 1698 } 1699 1700 if (location() == Plasma::Types::TopEdge 1701 && m_visibility->mode() != Latte::Types::WindowsCanCover 1702 && m_visibility->mode() != Latte::Types::WindowsAlwaysCover) { 1703 //! this is needed in order to preserve that the top dock will be above others. 1704 //! Unity layout paradigm is a good example for this. The top panel shadow 1705 //! should be always on top compared to left panel 1706 m_visibility->setViewOnFrontLayer(); 1707 } 1708 } 1709 1710 void View::verticalUnityViewHasFocus() 1711 { 1712 if (formFactor() == Plasma::Types::Vertical 1713 && (y() != screenGeometry().y()) 1714 && ( (m_alignment == Latte::Types::Justify && m_maxLength == 1.0) 1715 ||(m_alignment == Latte::Types::Top && m_offset == 0.0) )) { 1716 emit m_corona->verticalUnityViewHasFocus(); 1717 } 1718 } 1719 //! END: WORKAROUND 1720 1721 //!BEGIN configuration functions 1722 void View::saveConfig() 1723 { 1724 if (!this->containment()) { 1725 return; 1726 } 1727 1728 auto config = this->containment()->config(); 1729 config.writeEntry("onPrimary", onPrimary()); 1730 config.writeEntry("byPassWM", byPassWM()); 1731 config.writeEntry("isPreferredForShortcuts", isPreferredForShortcuts()); 1732 config.writeEntry("name", m_name); 1733 config.writeEntry("viewType", (int)m_type); 1734 } 1735 1736 void View::restoreConfig() 1737 { 1738 if (!this->containment()) { 1739 return; 1740 } 1741 1742 auto config = this->containment()->config(); 1743 m_onPrimary = config.readEntry("onPrimary", true); 1744 m_alignment = static_cast<Latte::Types::Alignment>(config.group("General").readEntry("alignment", (int)Latte::Types::Center)); 1745 m_byPassWM = config.readEntry("byPassWM", false); 1746 m_isPreferredForShortcuts = config.readEntry("isPreferredForShortcuts", false); 1747 m_name = config.readEntry("name", QString()); 1748 1749 //! Send changed signals at the end in order to be sure that saveConfig 1750 //! wont rewrite default/invalid values 1751 emit alignmentChanged(); 1752 emit nameChanged(); 1753 emit onPrimaryChanged(); 1754 emit byPassWMChanged(); 1755 } 1756 //!END configuration functions 1757 1758 } 1759 //!END namespace