diff --git a/app/dock/dockview.cpp b/app/dock/dockview.cpp index 83f9d192..6b1c81dd 100644 --- a/app/dock/dockview.cpp +++ b/app/dock/dockview.cpp @@ -1,1232 +1,1216 @@ /* * 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 "dockview.h" #include "dockconfigview.h" #include "dockmenumanager.h" #include "effects.h" #include "panelshadows_p.h" #include "positioner.h" #include "visibilitymanager.h" #include "../dockcorona.h" #include "../layout.h" #include "../layoutmanager.h" #include "../screenpool.h" #include "../plasmathemeextended.h" #include "../universalsettings.h" #include "../../liblattedock/extras.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 //! are needed in order for window flags to be set correctly DockView::DockView(Plasma::Corona *corona, QScreen *targetScreen, bool dockWindowBehavior) : PlasmaQuick::ContainmentView(corona), m_menuManager(new DockMenuManager(this)), m_effects(new View::Effects(this)), m_positioner(new View::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 { setFlags(flags | Qt::BypassWindowManagerHint); } KWindowSystem::setOnAllDesktops(winId(), true); if (targetScreen) m_positioner->setScreenToFollow(targetScreen); else m_positioner->setScreenToFollow(qGuiApp->primaryScreen()); connect(this, &DockView::containmentChanged , this, [ &, dockWindowBehavior]() { 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); //! 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 *dockCorona = qobject_cast(this->corona()); if (dockCorona) { connect(dockCorona, &DockCorona::docksCountChanged, this, &DockView::docksCountChanged); connect(this, &DockView::docksCountChanged, this, &DockView::totalDocksCountChanged); connect(dockCorona, &DockCorona::dockLocationChanged, this, &DockView::dockLocationChanged); } } DockView::~DockView() { m_inDelete = true; disconnect(corona(), &Plasma::Corona::availableScreenRectChanged, this, &DockView::availableScreenRectChanged); disconnect(containment(), SIGNAL(statusChanged(Plasma::Types::ItemStatus)), this, SLOT(statusChanged(Plasma::Types::ItemStatus))); qDebug() << "dock view deleting..."; rootContext()->setContextProperty(QStringLiteral("dock"), nullptr); //! this disconnect does not free up connections correctly when //! dockView 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_menuManager) { delete m_menuManager; } //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 DockView::init() { connect(this, &QQuickWindow::screenChanged, this, &DockView::docksCountChanged); connect(this, &QQuickWindow::xChanged, this, &DockView::xChanged); connect(this, &QQuickWindow::xChanged, this, &DockView::updateAbsDockGeometry); connect(this, &QQuickWindow::yChanged, this, &DockView::yChanged); connect(this, &QQuickWindow::yChanged, this, &DockView::updateAbsDockGeometry); connect(this, &QQuickWindow::widthChanged, this, &DockView::widthChanged); connect(this, &QQuickWindow::widthChanged, this, &DockView::updateAbsDockGeometry); connect(this, &QQuickWindow::heightChanged, this, &DockView::heightChanged); connect(this, &QQuickWindow::heightChanged, this, &DockView::updateAbsDockGeometry); connect(corona(), &Plasma::Corona::availableScreenRectChanged, this, &DockView::availableScreenRectChanged); connect(m_positioner, &View::Positioner::currentScreenChanged, this, &DockView::currentScreenChanged); connect(m_positioner, &View::Positioner::onHideWindowsForSlidingOut, this, &DockView::hideWindowsForSlidingOut); connect(m_positioner, &View::Positioner::screenGeometryChanged, this, &DockView::screenGeometryChanged); connect(this, &DockView::dockWinBehaviorChanged, this, &DockView::saveConfig); connect(this, &DockView::onPrimaryChanged, this, &DockView::saveConfig); connect(this, &DockView::isPreferredForShortcutsChanged, this, &DockView::saveConfig); connect(&m_theme, &Plasma::Theme::themeChanged, this, &DockView::themeChanged); connect(&m_theme, &Plasma::Theme::themeChanged, this, &DockView::themeHasShadowChanged); connect(this, SIGNAL(normalThicknessChanged()), corona(), SIGNAL(availableScreenRectChanged())); - connect(this, SIGNAL(shadowChanged()), corona(), SIGNAL(availableScreenRectChanged())); connect(m_menuManager, &DockMenuManager::contextMenuChanged, this, &DockView::contextMenuIsShownChanged); ///!!!!! rootContext()->setContextProperty(QStringLiteral("dock"), this); auto *dockCorona = qobject_cast(this->corona()); if (dockCorona) { rootContext()->setContextProperty(QStringLiteral("universalSettings"), dockCorona->universalSettings()); rootContext()->setContextProperty(QStringLiteral("layoutManager"), dockCorona->layoutManager()); rootContext()->setContextProperty(QStringLiteral("themeExtended"), dockCorona->themeExtended()); } setSource(corona()->kPackage().filePath("lattedockui")); // setVisible(true); m_positioner->syncGeometry(); if (!KWindowSystem::isPlatformWayland()) { setVisible(true); } qDebug() << "SOURCE:" << source(); } bool DockView::inDelete() const { return m_inDelete; } void DockView::disconnectSensitiveSignals() { disconnect(corona(), &Plasma::Corona::availableScreenRectChanged, this, &DockView::availableScreenRectChanged); setManagedLayout(nullptr); if (visibility()) { visibility()->setEnabledDynamicBackground(false); } } void DockView::availableScreenRectChanged() { if (m_inDelete) return; if (formFactor() == Plasma::Types::Vertical) { m_positioner->syncGeometry(); } } void DockView::setupWaylandIntegration() { if (m_shellSurface) return; if (DockCorona *c = qobject_cast(corona())) { using namespace KWayland::Client; PlasmaShell *interface {c->waylandDockCoronaInterface()}; 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 *DockView::surface() { return m_shellSurface; } //! the main function which decides if this dock is at the //! correct screen void DockView::reconsiderScreen() { m_positioner->reconsiderScreen(); } void DockView::addNewDock() { auto *dockCorona = qobject_cast(this->corona()); if (dockCorona) { dockCorona->loadDefaultLayout(); } } void DockView::copyDock() { m_managedLayout->copyDock(containment()); } void DockView::removeDock() { if (totalDocksCount() > 1) { QAction *removeAct = this->containment()->actions()->action(QStringLiteral("remove")); if (removeAct) { removeAct->trigger(); } } } QQmlListProperty DockView::screens() { return QQmlListProperty(this, nullptr, &countScreens, &atScreens); } int DockView::countScreens(QQmlListProperty *property) { Q_UNUSED(property) return qGuiApp->screens().count(); } QScreen *DockView::atScreens(QQmlListProperty *property, int index) { Q_UNUSED(property) return qGuiApp->screens().at(index); } QString DockView::currentScreen() const { return m_positioner->currentScreenName(); } bool DockView::settingsWindowIsShown() { auto configView = qobject_cast(m_configView); return (configView != nullptr); } void DockView::showSettingsWindow() { showConfigurationInterface(containment()); applyActivitiesToWindows(); } void DockView::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 DockView::localGeometry() const { return m_localGeometry; } void DockView::setLocalGeometry(const QRect &geometry) { if (m_localGeometry == geometry) { return; } m_localGeometry = geometry; emit localGeometryChanged(); updateAbsDockGeometry(); } void DockView::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 DockView::statusChanged(Plasma::Types::ItemStatus status) { if (containment()) { if (containment()->status() >= Plasma::Types::NeedsAttentionStatus && containment()->status() != Plasma::Types::HiddenStatus) { setBlockHiding(true); } else { setBlockHiding(false); } } } bool DockView::alternativesIsShown() const { return m_alternativesIsShown; } void DockView::setAlternativesIsShown(bool show) { if (m_alternativesIsShown == show) { return; } m_alternativesIsShown = show; setBlockHiding(show); emit alternativesIsShownChanged(); } bool DockView::contextMenuIsShown() const { if (!m_menuManager) { return false; } return m_menuManager->contextMenu(); } int DockView::currentThickness() const { if (formFactor() == Plasma::Types::Vertical) { - return m_effects->mask().isNull() ? width() : m_effects->mask().width() - m_shadow; + 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_shadow; + return m_effects->mask().isNull() ? height() : m_effects->mask().height() - m_effects->innerShadow(); } } int DockView::normalThickness() const { return m_normalThickness; } void DockView::setNormalThickness(int thickness) { if (m_normalThickness == thickness) { return; } m_normalThickness = thickness; emit normalThicknessChanged(); } int DockView::docksCount() const { if (!m_managedLayout) { return 0; } return m_managedLayout->docksCount(screen()); } int DockView::totalDocksCount() const { if (!m_managedLayout) { return 0; } return m_managedLayout->docksCount(); } int DockView::docksWithTasks() { if (!m_managedLayout) return 0; return m_managedLayout->noDocksWithTasks(); } bool DockView::dockWinBehavior() const { return m_dockWinBehavior; } void DockView::setDockWinBehavior(bool dock) { if (m_dockWinBehavior == dock) { return; } m_dockWinBehavior = dock; emit dockWinBehaviorChanged(); } bool DockView::behaveAsPlasmaPanel() const { return m_behaveAsPlasmaPanel; } void DockView::setBehaveAsPlasmaPanel(bool behavior) { if (m_behaveAsPlasmaPanel == behavior) { return; } m_behaveAsPlasmaPanel = behavior; if (m_behaveAsPlasmaPanel && m_effects->drawShadows()) { PanelShadows::self()->addWindow(this, m_effects->enabledBorders()); } else { PanelShadows::self()->removeWindow(this); } emit behaveAsPlasmaPanelChanged(); } bool DockView::inEditMode() const { return m_inEditMode; } void DockView::setInEditMode(bool edit) { if (m_inEditMode == edit) { return; } m_inEditMode = edit; emit inEditModeChanged(); } bool DockView::isPreferredForShortcuts() const { return m_isPreferredForShortcuts; } void DockView::setIsPreferredForShortcuts(bool preferred) { if (m_isPreferredForShortcuts == preferred) { return; } m_isPreferredForShortcuts = preferred; emit isPreferredForShortcutsChanged(); if (m_isPreferredForShortcuts && m_managedLayout) { emit m_managedLayout->preferredViewForShortcutsChanged(this); } } void DockView::preferredViewForShortcutsChangedSlot(DockView *view) { if (view != this) { setIsPreferredForShortcuts(false); } } bool DockView::onPrimary() const { return m_onPrimary; } void DockView::setOnPrimary(bool flag) { if (m_onPrimary == flag) { return; } m_onPrimary = flag; emit onPrimaryChanged(); } float DockView::maxLength() const { return m_maxLength; } void DockView::setMaxLength(float length) { if (m_maxLength == length) { return; } m_maxLength = length; emit maxLengthChanged(); } int DockView::maxThickness() const { return m_maxThickness; } void DockView::setMaxThickness(int thickness) { if (m_maxThickness == thickness) return; m_maxThickness = thickness; emit maxThicknessChanged(); } int DockView::alignment() const { return m_alignment; } void DockView::setAlignment(int alignment) { Dock::Alignment align = static_cast(alignment); if (m_alignment == alignment) { return; } m_alignment = align; emit alignmentChanged(); } bool DockView::blockAnimations() const { return m_blockAnimations; } void DockView::setBlockAnimations(bool block) { if (m_blockAnimations == block) { return; } m_blockAnimations = block; emit blockAnimationsChanged(); } bool DockView::colorizerSupport() const { return m_colorizerSupport; } void DockView::setColorizerSupport(bool support) { if (m_colorizerSupport == support) { return; } m_colorizerSupport = support; emit colorizerSupportChanged(); } bool DockView::themeHasShadow() const { return PanelShadows::self()->enabled(); } QRect DockView::absGeometry() const { return m_absGeometry; } QRect DockView::screenGeometry() const { if (this->screen()) { QRect geom = this->screen()->geometry(); return geom; } return QRect(); } int DockView::offset() const { return m_offset; } void DockView::setOffset(int offset) { if (m_offset == offset) { return; } m_offset = offset; emit offsetChanged(); } int DockView::dockTransparency() const { return m_dockTransparency; } void DockView::setDockTransparency(int transparency) { if (m_dockTransparency == transparency) { return; } m_dockTransparency = transparency; emit dockTransparencyChanged(); } -int DockView::shadow() const -{ - return m_shadow; -} - -void DockView::setShadow(int shadow) -{ - if (m_shadow == shadow) - return; - - m_shadow = shadow; - - emit shadowChanged(); -} - int DockView::fontPixelSize() const { return m_fontPixelSize; } void DockView::setFontPixelSize(int size) { if (m_fontPixelSize == size) { return; } m_fontPixelSize = size; emit fontPixelSizeChanged(); } void DockView::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 *DockView::managedLayout() const { return m_managedLayout; } void DockView::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, &DockView::preferredViewForShortcutsChangedSlot); } DockCorona *dockCorona = qobject_cast(this->corona()); if (dockCorona->layoutManager()->memoryUsage() == Dock::MultipleLayouts) { connectionsManagedLayout[1] = connect(dockCorona->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(dockCorona->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 DockView::moveToLayout(QString layoutName) { if (!m_managedLayout) { return; } QList containments = m_managedLayout->unassignFromLayout(this); DockCorona *dockCorona = qobject_cast(this->corona()); if (dockCorona && containments.size() > 0) { Layout *newLayout = dockCorona->layoutManager()->activeLayout(layoutName); if (newLayout) { newLayout->assignToLayout(this, containments); } } } void DockView::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 DockView::hideWindowsForSlidingOut() { setBlockHiding(false); if (m_configView) { auto configDialog = qobject_cast(m_configView); if (configDialog) { configDialog->hideConfigWindow(); } } } //! remove latte tasks plasmoid void DockView::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 DockView::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 DockView::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 DockView::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; } View::Effects *DockView::effects() const { return m_effects; } View::Positioner *DockView::positioner() const { return m_positioner; } VisibilityManager *DockView::visibility() const { return m_visibility; } bool DockView::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(); if (m_effects->drawShadows()) { PanelShadows::self()->addWindow(this, m_effects->enabledBorders()); } } break; case QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed: if (m_shellSurface) { delete m_shellSurface; m_shellSurface = nullptr; qDebug() << "WAYLAND dock window surface was deleted..."; PanelShadows::self()->removeWindow(this); } break; } } break; default: break; } } return ContainmentView::event(e);; } QList DockView::freeEdges() const { if (!m_managedLayout) { const QList emptyEdges; return emptyEdges; } const auto edges = m_managedLayout->freeEdges(screen()); QList edgesInt; foreach (Plasma::Types::Location edge, edges) { edgesInt.append(static_cast(edge)); } return edgesInt; } void DockView::deactivateApplets() { if (!containment()) { return; } foreach (auto applet, containment()->applets()) { PlasmaQuick::AppletQuickItem *ai = applet->property("_plasma_graphicObject").value(); if (ai) { ai->setExpanded(false); } } } void DockView::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 DockView::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 DockView::disableGrabItemBehavior() { setMouseGrabEnabled(false); } void DockView::restoreGrabItemBehavior() { setMouseGrabEnabled(true); if (mouseGrabberItem()) { mouseGrabberItem()->ungrabMouse(); } } //!BEGIN overriding context menus behavior void DockView::mousePressEvent(QMouseEvent *event) { bool result = m_menuManager->mousePressEvent(event); emit contextMenuIsShownChanged(); if (result) { PlasmaQuick::ContainmentView::mousePressEvent(event); } } //!END overriding context menus behavior //!BEGIN configuration functions void DockView::saveConfig() { if (!this->containment()) return; auto config = this->containment()->config(); config.writeEntry("onPrimary", onPrimary()); config.writeEntry("dockWindowBehavior", dockWinBehavior()); config.writeEntry("isPreferredForShortcuts", isPreferredForShortcuts()); config.sync(); } void DockView::restoreConfig() { if (!this->containment()) return; auto config = this->containment()->config(); m_onPrimary = config.readEntry("onPrimary", true); m_dockWinBehavior = config.readEntry("dockWindowBehavior", true); 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(); } //!END configuration functions } //!END namespace diff --git a/app/dock/dockview.h b/app/dock/dockview.h index 87e40e64..dcbc79a1 100644 --- a/app/dock/dockview.h +++ b/app/dock/dockview.h @@ -1,337 +1,331 @@ /* * 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 DOCKVIEW_H #define DOCKVIEW_H #include "dockconfigview.h" #include "effects.h" #include "positioner.h" #include "visibilitymanager.h" #include "../layout.h" #include "../plasmaquick/containmentview.h" #include "../plasmaquick/configview.h" #include "../../liblattedock/dock.h" #include #include #include #include #include #include #include #include #include namespace Plasma { class Types; class Corona; class Containment; } namespace KWayland { namespace Client { class PlasmaShellSurface; } } namespace Latte { class DockMenuManager; class Layout; } namespace Latte { class DockView : 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 blockAnimations READ blockAnimations WRITE setBlockAnimations NOTIFY blockAnimationsChanged) Q_PROPERTY(bool colorizerSupport READ colorizerSupport WRITE setColorizerSupport NOTIFY colorizerSupportChanged) 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 themeHasShadow READ themeHasShadow NOTIFY themeHasShadowChanged) Q_PROPERTY(bool onPrimary READ onPrimary WRITE setOnPrimary NOTIFY onPrimaryChanged) Q_PROPERTY(int alignment READ alignment WRITE setAlignment NOTIFY alignmentChanged) Q_PROPERTY(int docksCount READ docksCount NOTIFY docksCountChanged) Q_PROPERTY(int dockTransparency READ dockTransparency WRITE setDockTransparency NOTIFY dockTransparencyChanged) Q_PROPERTY(int fontPixelSize READ fontPixelSize WRITE setFontPixelSize NOTIFY fontPixelSizeChanged) Q_PROPERTY(int totalDocksCount READ totalDocksCount NOTIFY totalDocksCountChanged) 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(int shadow READ shadow WRITE setShadow NOTIFY shadowChanged) Q_PROPERTY(QString currentScreen READ currentScreen NOTIFY currentScreenChanged) Q_PROPERTY(float maxLength READ maxLength WRITE setMaxLength NOTIFY maxLengthChanged) Q_PROPERTY(Latte::View::Effects *effects READ effects NOTIFY effectsChanged) Q_PROPERTY(Layout *managedLayout READ managedLayout WRITE setManagedLayout NOTIFY managedLayoutChanged) Q_PROPERTY(Latte::View::Positioner *positioner READ positioner NOTIFY positionerChanged) Q_PROPERTY(VisibilityManager *visibility READ visibility NOTIFY visibilityChanged) Q_PROPERTY(QQmlListProperty screens READ screens) 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: DockView(Plasma::Corona *corona, QScreen *targetScreen = nullptr, bool dockWindowBehavior = false); virtual ~DockView(); void init(); bool alternativesIsShown() const; void setAlternativesIsShown(bool show); bool inDelete() const; bool onPrimary() const; void setOnPrimary(bool flag); int currentThickness() const; int docksCount() const; int totalDocksCount() const; bool behaveAsPlasmaPanel() const; void setBehaveAsPlasmaPanel(bool behavior); bool blockAnimations() const; void setBlockAnimations(bool block); bool colorizerSupport() const; void setColorizerSupport(bool support); bool contextMenuIsShown() const; bool dockWinBehavior() const; void setDockWinBehavior(bool dock); bool inEditMode() const; void setInEditMode(bool edit); bool isPreferredForShortcuts() const; void setIsPreferredForShortcuts(bool preferred); bool themeHasShadow() const; float maxLength() const; void setMaxLength(float length); int dockTransparency() const; void setDockTransparency(int transparency); 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 shadow() const; - void setShadow(int shadow); - int alignment() const; void setAlignment(int alignment); QRect absGeometry() const; QRect screenGeometry() const; QString currentScreen() const; QRect localGeometry() const; void setLocalGeometry(const QRect &geometry); bool settingsWindowIsShown(); void showSettingsWindow(); View::Effects *effects() const; View::Positioner *positioner() const; VisibilityManager *visibility() const; Layout *managedLayout() const; void setManagedLayout(Layout *layout); KWayland::Client::PlasmaShellSurface *surface(); void reconsiderScreen(); QQmlListProperty screens(); //! is needed by screens() static int countScreens(QQmlListProperty *property); //! is needed by screens() static QScreen *atScreens(QQmlListProperty *property, int index); //! 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 addNewDock(); Q_INVOKABLE void removeDock(); Q_INVOKABLE void copyDock(); Q_INVOKABLE QList freeEdges() const; 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 int docksWithTasks(); 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 blockAnimationsChanged(); void colorizerSupportChanged(); void contextMenuIsShownChanged(); void currentScreenChanged(); void dockLocationChanged(); void docksCountChanged(); void dockTransparencyChanged(); 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 shadowChanged(); void themeChanged(); void themeHasShadowChanged(); void totalDocksCountChanged(); void xChanged(); void yChanged(); void absGeometryChanged(const QRect &geometry); private slots: void availableScreenRectChanged(); void hideWindowsForSlidingOut(); void preferredViewForShortcutsChangedSlot(DockView *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_blockAnimations{false}; bool m_colorizerSupport{false}; bool m_dockWinBehavior{true}; bool m_inDelete{false}; bool m_inEditMode{false}; bool m_isPreferredForShortcuts{false}; bool m_onPrimary{true}; int m_dockTransparency{100}; int m_fontPixelSize{ -1}; int m_maxThickness{24}; int m_normalThickness{24}; int m_offset{0}; - int m_shadow{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_menuManager; QPointer m_effects; QPointer m_positioner; QPointer m_visibility; //! Connections to release and bound for the managed layout std::array connectionsManagedLayout; Plasma::Theme m_theme; KWayland::Client::PlasmaShellSurface *m_shellSurface{nullptr}; }; } #endif diff --git a/app/dock/effects.cpp b/app/dock/effects.cpp index b63e2306..b8c659a2 100644 --- a/app/dock/effects.cpp +++ b/app/dock/effects.cpp @@ -1,318 +1,335 @@ /* * Copyright 2018 Michail Vourlakos * * This file is part of Latte-Dock * * Latte-Dock is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * Latte-Dock is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "effects.h" #include "dockview.h" #include "panelshadows_p.h" #include "../../liblattedock/dock.h" #include #include #include namespace Latte { namespace View { Effects::Effects(Latte::DockView *parent) : QObject(parent), m_view(parent) { init(); } Effects::~Effects() { } void Effects::init() { connect(this, &Effects::drawEffectsChanged, this, &Effects::updateEffects); connect(this, &Effects::rectChanged, this, &Effects::updateEffects); connect(this, &Effects::drawShadowsChanged, this, [&]() { if (m_view->behaveAsPlasmaPanel()) { updateEnabledBorders(); } }); connect(m_view, &Latte::DockView::alignmentChanged, this, &Effects::updateEnabledBorders); connect(m_view, &Latte::DockView::behaveAsPlasmaPanelChanged, this, &Effects::updateEffects); connect(m_view, &Latte::DockView::dockTransparencyChanged, this, &Effects::updateEffects); + + connect(this, SIGNAL(innerShadowChanged()), m_view->corona(), SIGNAL(availableScreenRectChanged())); } bool Effects::drawShadows() const { return m_drawShadows; } void Effects::setDrawShadows(bool draw) { if (m_drawShadows == draw) { return; } m_drawShadows = draw; if (m_view->behaveAsPlasmaPanel() && m_drawShadows) { PanelShadows::self()->addWindow(m_view, m_enabledBorders); } else { PanelShadows::self()->removeWindow(m_view); } emit drawShadowsChanged(); } bool Effects::drawEffects() const { return m_drawEffects; } void Effects::setDrawEffects(bool draw) { if (m_drawEffects == draw) { return; } m_drawEffects = draw; emit drawEffectsChanged(); } bool Effects::forceDrawCenteredBorders() const { return m_forceDrawCenteredBorders; } void Effects::setForceDrawCenteredBorders(bool draw) { if (m_forceDrawCenteredBorders == draw) { return; } m_forceDrawCenteredBorders = draw; } +int Effects::innerShadow() const +{ + return m_innerShadow; +} + +void Effects::setInnerShadow(int shadow) +{ + if (m_innerShadow == shadow) + return; + + m_innerShadow = shadow; + + emit innerShadowChanged(); +} + QRect Effects::rect() const { return m_rect; } void Effects::setRect(QRect area) { QRect inWindowRect = area.intersected(QRect(0, 0, m_view->width(), m_view->height())); if (m_rect == inWindowRect) { return; } m_rect = inWindowRect; emit rectChanged(); } QRect Effects::mask() const { return m_mask; } void Effects::setMask(QRect area) { if (m_mask == area) return; m_mask = area; if (KWindowSystem::compositingActive()) { if (m_view->behaveAsPlasmaPanel()) { m_view->setMask(QRect()); } else { m_view->setMask(m_mask); } } else { //! this is used when compositing is disabled and provides //! the correct way for the mask to be painted in order for //! rounded corners to be shown correctly //! the enabledBorders check was added because there was cases //! that the mask region wasnt calculated correctly after location changes if (!m_background || m_background->enabledBorders() != m_enabledBorders) { m_background = new Plasma::FrameSvg(this); } if (m_background->imagePath() != "opaque/dialogs/background") { m_background->setImagePath(QStringLiteral("opaque/dialogs/background")); } m_background->setEnabledBorders(m_enabledBorders); m_background->resizeFrame(area.size()); QRegion fixedMask = m_background->mask(); fixedMask.translate(m_mask.x(), m_mask.y()); //! fix for KF5.32 that return empty QRegion's for the mask if (fixedMask.isEmpty()) { fixedMask = QRegion(m_mask); } m_view->setMask(fixedMask); } // qDebug() << "dock mask set:" << m_mask; emit maskChanged(); } void Effects::updateEffects() { //! Don't apply any effect before the wayland surface is created under wayland //! https://bugs.kde.org/show_bug.cgi?id=392890 if (KWindowSystem::isPlatformWayland() && !m_view->surface()) { return; } if (!m_view->behaveAsPlasmaPanel()) { if (m_drawEffects && !m_rect.isNull() && !m_rect.isEmpty()) { //! this is used when compositing is disabled and provides //! the correct way for the mask to be painted in order for //! rounded corners to be shown correctly if (!m_background) { m_background = new Plasma::FrameSvg(this); } if (m_background->imagePath() != "widgets/panel-background") { m_background->setImagePath(QStringLiteral("widgets/panel-background")); } m_background->setEnabledBorders(m_enabledBorders); m_background->resizeFrame(m_rect.size()); QRegion fixedMask = m_background->mask(); fixedMask.translate(m_rect.x(), m_rect.y()); //! fix1, for KF5.32 that return empty QRegion's for the mask if (fixedMask.isEmpty()) { fixedMask = QRegion(m_rect); } KWindowEffects::enableBlurBehind(m_view->winId(), true, fixedMask); bool drawBackgroundEffect = m_theme.backgroundContrastEnabled() && (m_view->dockTransparency() == 100); //based on Breeze Dark theme behavior the enableBackgroundContrast even though it does accept //a QRegion it uses only the first rect. The bug was that for Breeze Dark there was a line //at the dock bottom that was distinguishing it from other themes KWindowEffects::enableBackgroundContrast(m_view->winId(), drawBackgroundEffect, m_theme.backgroundContrast(), m_theme.backgroundIntensity(), m_theme.backgroundSaturation(), fixedMask.boundingRect()); } else { KWindowEffects::enableBlurBehind(m_view->winId(), false); KWindowEffects::enableBackgroundContrast(m_view->winId(), false); } } else if (m_view->behaveAsPlasmaPanel() && m_drawEffects) { KWindowEffects::enableBlurBehind(m_view->winId(), true); bool drawBackgroundEffect = m_theme.backgroundContrastEnabled() && (m_view->dockTransparency() == 100); KWindowEffects::enableBackgroundContrast(m_view->winId(), drawBackgroundEffect, m_theme.backgroundContrast(), m_theme.backgroundIntensity(), m_theme.backgroundSaturation()); } else { KWindowEffects::enableBlurBehind(m_view->winId(), false); KWindowEffects::enableBackgroundContrast(m_view->winId(), false); } } //!BEGIN draw panel shadows outside the dock window Plasma::FrameSvg::EnabledBorders Effects::enabledBorders() const { return m_enabledBorders; } void Effects::updateEnabledBorders() { if (!m_view->screen()) { return; } Plasma::FrameSvg::EnabledBorders borders = Plasma::FrameSvg::AllBorders; switch (m_view->location()) { case Plasma::Types::TopEdge: borders &= ~Plasma::FrameSvg::TopBorder; break; case Plasma::Types::LeftEdge: borders &= ~Plasma::FrameSvg::LeftBorder; break; case Plasma::Types::RightEdge: borders &= ~Plasma::FrameSvg::RightBorder; break; case Plasma::Types::BottomEdge: borders &= ~Plasma::FrameSvg::BottomBorder; break; default: break; } if ((m_view->location() == Plasma::Types::LeftEdge || m_view->location() == Plasma::Types::RightEdge)) { if (m_view->maxLength() == 1 && m_view->alignment() == Latte::Dock::Justify && !m_forceDrawCenteredBorders) { borders &= ~Plasma::FrameSvg::TopBorder; borders &= ~Plasma::FrameSvg::BottomBorder; } if (m_view->alignment() == Latte::Dock::Top && !m_forceDrawCenteredBorders && m_view->offset() == 0) { borders &= ~Plasma::FrameSvg::TopBorder; } if (m_view->alignment() == Latte::Dock::Bottom && !m_forceDrawCenteredBorders && m_view->offset() == 0) { borders &= ~Plasma::FrameSvg::BottomBorder; } } if (m_view->location() == Plasma::Types::TopEdge || m_view->location() == Plasma::Types::BottomEdge) { if (m_view->maxLength() == 1 && m_view->alignment() == Latte::Dock::Justify) { borders &= ~Plasma::FrameSvg::LeftBorder; borders &= ~Plasma::FrameSvg::RightBorder; } if (m_view->alignment() == Latte::Dock::Left && m_view->offset() == 0) { borders &= ~Plasma::FrameSvg::LeftBorder; } if (m_view->alignment() == Latte::Dock::Right && m_view->offset() == 0) { borders &= ~Plasma::FrameSvg::RightBorder; } } if (m_enabledBorders != borders) { m_enabledBorders = borders; emit enabledBordersChanged(); } if (!m_view->behaveAsPlasmaPanel() || !m_drawShadows) { PanelShadows::self()->removeWindow(m_view); } else { PanelShadows::self()->setEnabledBorders(m_view, borders); } } //!END draw panel shadows outside the dock window } } diff --git a/app/dock/effects.h b/app/dock/effects.h index 8c95c2a0..ac175005 100644 --- a/app/dock/effects.h +++ b/app/dock/effects.h @@ -1,104 +1,113 @@ /* * Copyright 2018 Michail Vourlakos * * This file is part of Latte-Dock * * Latte-Dock is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * Latte-Dock is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef EFFECTS_H #define EFFECTS_H #include #include #include #include #include namespace Latte { class DockView; } namespace Latte { namespace View { class Effects: public QObject { Q_OBJECT Q_PROPERTY(bool drawShadows READ drawShadows WRITE setDrawShadows NOTIFY drawShadowsChanged) Q_PROPERTY(bool drawEffects READ drawEffects WRITE setDrawEffects NOTIFY drawEffectsChanged) + //! thickness shadow size when is drawn inside the window from qml + Q_PROPERTY(int innerShadow READ innerShadow WRITE setInnerShadow NOTIFY innerShadowChanged) + Q_PROPERTY(QRect mask READ mask WRITE setMask NOTIFY maskChanged) Q_PROPERTY(QRect rect READ rect WRITE setRect NOTIFY rectChanged) Q_PROPERTY(Plasma::FrameSvg::EnabledBorders enabledBorders READ enabledBorders NOTIFY enabledBordersChanged) public: Effects(DockView *parent); virtual ~Effects(); bool drawShadows() const; void setDrawShadows(bool draw); bool drawEffects() const; void setDrawEffects(bool draw); bool forceDrawCenteredBorders() const; void setForceDrawCenteredBorders(bool draw); + int innerShadow() const; + void setInnerShadow(int shadow); + QRect mask() const; void setMask(QRect area); QRect rect() const; void setRect(QRect area); Plasma::FrameSvg::EnabledBorders enabledBorders() const; public slots: void updateEffects(); void updateEnabledBorders(); signals: void drawShadowsChanged(); void drawEffectsChanged(); void enabledBordersChanged(); void maskChanged(); + void innerShadowChanged(); void rectChanged(); private slots: void init(); private: bool m_drawShadows{true}; bool m_drawEffects{false}; bool m_forceDrawCenteredBorders{false}; + int m_innerShadow{0}; + QRect m_rect; QRect m_mask; QPointer m_view; Plasma::Theme m_theme; //only for the mask on disabled compositing, not to actually paint Plasma::FrameSvg *m_background{nullptr}; //only for the mask, not to actually paint Plasma::FrameSvg::EnabledBorders m_enabledBorders{Plasma::FrameSvg::AllBorders}; }; } } #endif diff --git a/app/dock/positioner.cpp b/app/dock/positioner.cpp index de7e7ae9..5926f6da 100644 --- a/app/dock/positioner.cpp +++ b/app/dock/positioner.cpp @@ -1,652 +1,652 @@ /* * Copyright 2018 Michail Vourlakos * * This file is part of Latte-Dock * * Latte-Dock is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * Latte-Dock is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "positioner.h" #include "dockview.h" #include "effects.h" #include "../dockcorona.h" #include "../screenpool.h" #include "../universalsettings.h" #include "../../liblattedock/dock.h" #include #include #include #include namespace Latte { namespace View { Positioner::Positioner(Latte::DockView *parent) : QObject(parent), m_view(parent) { m_screenSyncTimer.setSingleShot(true); m_screenSyncTimer.setInterval(2000); connect(&m_screenSyncTimer, &QTimer::timeout, this, &Positioner::reconsiderScreen); //! under X11 it was identified that windows many times especially under screen changes //! don't end up at the correct position and size. This timer will enforce repositionings //! and resizes every 500ms if the window hasn't end up to correct values and until this //! is achieved m_validateGeometryTimer.setSingleShot(true); m_validateGeometryTimer.setInterval(500); connect(&m_validateGeometryTimer, &QTimer::timeout, this, &Positioner::syncGeometry); auto *dockCorona = qobject_cast(m_view->corona()); if (dockCorona) { m_screenSyncTimer.setInterval(qMax(dockCorona->universalSettings()->screenTrackerInterval() - 500, 1000)); connect(dockCorona->universalSettings(), &UniversalSettings::screenTrackerIntervalChanged, this, [this, dockCorona]() { m_screenSyncTimer.setInterval(qMax(dockCorona->universalSettings()->screenTrackerInterval() - 500, 1000)); }); connect(dockCorona, &DockCorona::dockLocationChanged, this, [&]() { //! check if an edge has been freed for a primary dock //! from another screen if (m_view->onPrimary()) { m_screenSyncTimer.start(); } }); } init(); } Positioner::~Positioner() { m_inDelete = true; m_screenSyncTimer.stop(); m_validateGeometryTimer.stop(); } void Positioner::init() { //! connections connect(this, &Positioner::screenGeometryChanged, this, &Positioner::syncGeometry); connect(m_view, &QQuickWindow::xChanged, this, &Positioner::validateDockGeometry); connect(m_view, &QQuickWindow::yChanged, this, &Positioner::validateDockGeometry); connect(m_view, &QQuickWindow::widthChanged, this, &Positioner::validateDockGeometry); connect(m_view, &QQuickWindow::heightChanged, this, &Positioner::validateDockGeometry); connect(m_view, &QQuickWindow::screenChanged, this, &Positioner::screenChanged); connect(m_view, &Latte::DockView::absGeometryChanged, this, &Positioner::syncGeometry); connect(m_view, &Latte::DockView::behaveAsPlasmaPanelChanged, this, &Positioner::syncGeometry); connect(m_view, &Latte::DockView::maxThicknessChanged, this, &Positioner::syncGeometry); connect(m_view, &Latte::DockView::maxLengthChanged, this, &Positioner::syncGeometry); connect(m_view, &Latte::DockView::offsetChanged, this, &Positioner::syncGeometry); connect(m_view, &Latte::DockView::locationChanged, this, [&]() { updateFormFactor(); syncGeometry(); }); connect(m_view, &Latte::DockView::normalThicknessChanged, this, [&]() { if (m_view->behaveAsPlasmaPanel()) { syncGeometry(); } }); - connect(m_view, &Latte::DockView::shadowChanged, this, [&]() { - if (m_view->behaveAsPlasmaPanel()) { + connect(m_view->effects(), &Latte::View::Effects::drawShadowsChanged, this, [&]() { + if (!m_view->behaveAsPlasmaPanel()) { syncGeometry(); } }); - connect(m_view->effects(), &Latte::View::Effects::drawShadowsChanged, this, [&]() { - if (!m_view->behaveAsPlasmaPanel()) { + connect(m_view->effects(), &Latte::View::Effects::innerShadowChanged, this, [&]() { + if (m_view->behaveAsPlasmaPanel()) { syncGeometry(); } }); connect(qGuiApp, &QGuiApplication::screenAdded, this, &Positioner::screenChanged); connect(qGuiApp, &QGuiApplication::primaryScreenChanged, this, &Positioner::screenChanged); initSignalingForLocationChangeSliding(); } QString Positioner::currentScreenName() const { return m_screenToFollowId; } bool Positioner::setCurrentScreen(const QString id) { QScreen *nextScreen{qGuiApp->primaryScreen()}; if (id != "primary") { foreach (auto scr, qGuiApp->screens()) { if (scr && scr->name() == id) { nextScreen = scr; break; } } } if (m_screenToFollow == nextScreen) { return true; } if (nextScreen) { if (m_view->managedLayout()) { auto freeEdges = m_view->managedLayout()->freeEdges(nextScreen); if (!freeEdges.contains(m_view->location())) { return false; } else { m_goToScreen = nextScreen; //! asynchronous call in order to not crash from configwindow //! deletion from sliding out animation QTimer::singleShot(100, [this]() { emit hideDockDuringScreenChangeStarted(); }); } } } return true; } //! this function updates the dock's associated screen. //! updateScreenId = true, update also the m_screenToFollowId //! updateScreenId = false, do not update the m_screenToFollowId //! that way an explicit dock can be shown in another screen when //! there isnt a tasks dock running in the system and for that //! dock its first origin screen is stored and that way when //! that screen is reconnected the dock will return to its original //! place void Positioner::setScreenToFollow(QScreen *scr, bool updateScreenId) { if (!scr || (scr && (m_screenToFollow == scr) && (m_view->screen() == scr))) { return; } qDebug() << "setScreenToFollow() called for screen:" << scr->name() << " update:" << updateScreenId; m_screenToFollow = scr; if (updateScreenId) { m_screenToFollowId = scr->name(); } qDebug() << "adapting to screen..."; m_view->setScreen(scr); if (m_view->containment()) { m_view->containment()->reactToScreenChange(); } connect(scr, &QScreen::geometryChanged, this, &Positioner::screenGeometryChanged); syncGeometry(); m_view->updateAbsDockGeometry(true); qDebug() << "setScreenToFollow() ended..."; emit screenGeometryChanged(); emit currentScreenChanged(); } //! the main function which decides if this dock is at the //! correct screen void Positioner::reconsiderScreen() { if (m_inDelete) { return; } qDebug() << "reconsiderScreen() called..."; qDebug() << " Delayer "; foreach (auto scr, qGuiApp->screens()) { qDebug() << " D, found screen: " << scr->name(); } bool screenExists{false}; //!check if the associated screen is running foreach (auto scr, qGuiApp->screens()) { if (m_screenToFollowId == scr->name() || (m_view->onPrimary() && scr == qGuiApp->primaryScreen())) { screenExists = true; } } qDebug() << "dock screen exists ::: " << screenExists; //! 1.a primary dock must be always on the primary screen if (m_view->onPrimary() && (m_screenToFollowId != qGuiApp->primaryScreen()->name() || m_screenToFollow != qGuiApp->primaryScreen() || m_view->screen() != qGuiApp->primaryScreen())) { using Plasma::Types; QList edges{Types::BottomEdge, Types::LeftEdge, Types::TopEdge, Types::RightEdge}; edges = m_view->managedLayout() ? m_view->managedLayout()->availableEdgesForView(qGuiApp->primaryScreen(), m_view) : edges; //change to primary screen only if the specific edge is free qDebug() << "updating the primary screen for dock..."; qDebug() << "available primary screen edges:" << edges; qDebug() << "dock location:" << m_view->location(); if (edges.contains(m_view->location())) { //! case 1 qDebug() << "reached case 1: of updating dock primary screen..."; setScreenToFollow(qGuiApp->primaryScreen()); } } else if (!m_view->onPrimary()) { //! 2.an explicit dock must be always on the correct associated screen //! there are cases that window manager misplaces the dock, this function //! ensures that this dock will return at its correct screen foreach (auto scr, qGuiApp->screens()) { if (scr && scr->name() == m_screenToFollowId) { qDebug() << "reached case 2: updating the explicit screen for dock..."; setScreenToFollow(scr); break; } } } syncGeometry(); qDebug() << "reconsiderScreen() ended..."; emit m_view->docksCountChanged(); } void Positioner::screenChanged(QScreen *scr) { m_screenSyncTimer.start(); //! this is needed in order to update the struts on screen change //! and even though the geometry has been set correctly the offsets //! of the screen must be updated to the new ones if (m_view->visibility() && m_view->visibility()->mode() == Latte::Dock::AlwaysVisible) { m_view->updateAbsDockGeometry(true); } } void Positioner::syncGeometry() { if (!(m_view->screen() && m_view->containment()) || m_inDelete) { return; } bool found{false}; qDebug() << "syncGeometry() called..."; //! before updating the positioning and geometry of the dock //! we make sure that the dock is at the correct screen if (m_view->screen() != m_screenToFollow) { qDebug() << "Sync Geometry screens inconsistent!!!! "; if (m_screenToFollow) { qDebug() << "Sync Geometry screens inconsistent for m_screenToFollow:" << m_screenToFollow->name() << " dock screen:" << m_view->screen()->name(); } if (!m_screenSyncTimer.isActive()) { m_screenSyncTimer.start(); } } else { found = true; } //! if the dock isnt at the correct screen the calculations //! are not executed if (found) { //! compute the free screen rectangle for vertical panels only once //! this way the costly QRegion computations are calculated only once //! instead of two times (both inside the resizeWindow and the updatePosition) QRegion freeRegion;; QRect maximumRect; QRect availableScreenRect{m_view->screen()->geometry()}; if (m_view->formFactor() == Plasma::Types::Vertical) { QString layoutName = m_view->managedLayout() ? m_view->managedLayout()->name() : QString(); auto dockCorona = qobject_cast(m_view->corona()); int fixedScreen = m_view->onPrimary() ? dockCorona->screenPool()->primaryScreenId() : m_view->containment()->screen(); freeRegion = dockCorona->availableScreenRegionWithCriteria(fixedScreen, layoutName); maximumRect = maximumNormalGeometry(); QRegion availableRegion = freeRegion.intersected(maximumRect); availableScreenRect = freeRegion.intersected(maximumRect).boundingRect(); float area = 0; //! it is used to choose which or the availableRegion rectangles will //! be the one representing dock geometry for (int i = 0; i < availableRegion.rectCount(); ++i) { QRect rect = availableRegion.rects().at(i); //! the area of each rectangle in calculated in squares of 50x50 //! this is a way to avoid enourmous numbers for area value float tempArea = (float)(rect.width() * rect.height()) / 2500; if (tempArea > area) { availableScreenRect = rect; area = tempArea; } } if (availableRegion.rectCount() > 1 && m_view->behaveAsPlasmaPanel()) { m_view->effects()->setForceDrawCenteredBorders(true); } else { m_view->effects()->setForceDrawCenteredBorders(false); } } else { m_view->effects()->setForceDrawCenteredBorders(false); } m_view->effects()->updateEnabledBorders(); resizeWindow(availableScreenRect); updatePosition(availableScreenRect); qDebug() << "syncGeometry() calculations for screen: " << m_view->screen()->name() << " _ " << m_view->screen()->geometry(); } qDebug() << "syncGeometry() ended..."; // qDebug() << "dock geometry:" << qRectToStr(geometry()); } void Positioner::validateDockGeometry() { if (m_view->geometry() != m_validGeometry) { m_validateGeometryTimer.start(); } } //! this is used mainly from vertical panels in order to //! to get the maximum geometry that can be used from the dock //! based on their alignment type and the location dock QRect Positioner::maximumNormalGeometry() { int xPos = 0; int yPos = 0; int maxHeight = m_view->maxLength() * m_view->screen()->geometry().height(); int maxWidth = m_view->normalThickness(); QRect maxGeometry; maxGeometry.setRect(0, 0, maxWidth, maxHeight); switch (m_view->location()) { case Plasma::Types::LeftEdge: xPos = m_view->screen()->geometry().x(); switch (m_view->alignment()) { case Latte::Dock::Top: yPos = m_view->screen()->geometry().y(); break; case Latte::Dock::Center: case Latte::Dock::Justify: yPos = qMax(m_view->screen()->geometry().center().y() - maxHeight / 2, m_view->screen()->geometry().y()); break; case Latte::Dock::Bottom: yPos = m_view->screen()->geometry().bottom() - maxHeight + 1; break; } maxGeometry.setRect(xPos, yPos, maxWidth, maxHeight); break; case Plasma::Types::RightEdge: xPos = m_view->screen()->geometry().right() - maxWidth + 1; switch (m_view->alignment()) { case Latte::Dock::Top: yPos = m_view->screen()->geometry().y(); break; case Latte::Dock::Center: case Latte::Dock::Justify: yPos = qMax(m_view->screen()->geometry().center().y() - maxHeight / 2, m_view->screen()->geometry().y()); break; case Latte::Dock::Bottom: yPos = m_view->screen()->geometry().bottom() - maxHeight + 1; break; } maxGeometry.setRect(xPos, yPos, maxWidth, maxHeight); break; default: //! bypass clang warnings break; } //! this is needed in order to preserve that the top dock will be above //! the others in case flag bypasswindowmanagerhint hasn't be set, //! such a case is the AlwaysVisible mode if (m_view->location() == Plasma::Types::TopEdge) { KWindowSystem::setState(m_view->winId(), NET::KeepAbove); } else { KWindowSystem::clearState(m_view->winId(), NET::KeepAbove); } return maxGeometry; } void Positioner::updatePosition(QRect availableScreenRect) { QRect screenGeometry{availableScreenRect}; QPoint position; position = {0, 0}; const auto length = [&](int length) -> int { float offs = static_cast(m_view->offset()); return static_cast(length * ((1 - m_view->maxLength()) / 2) + length * (offs / 100)); }; - int cleanThickness = m_view->normalThickness() - m_view->shadow(); + int cleanThickness = m_view->normalThickness() - m_view->effects()->innerShadow(); switch (m_view->location()) { case Plasma::Types::TopEdge: if (m_view->behaveAsPlasmaPanel()) { position = {screenGeometry.x() + length(screenGeometry.width()), screenGeometry.y()}; } else { position = {screenGeometry.x(), screenGeometry.y()}; } break; case Plasma::Types::BottomEdge: if (m_view->behaveAsPlasmaPanel()) { position = {screenGeometry.x() + length(screenGeometry.width()), screenGeometry.y() + screenGeometry.height() - cleanThickness }; } else { position = {screenGeometry.x(), screenGeometry.y() + screenGeometry.height() - m_view->height()}; } break; case Plasma::Types::RightEdge: if (m_view->behaveAsPlasmaPanel() && !m_view->mask().isNull()) { position = {availableScreenRect.right() - cleanThickness + 1, availableScreenRect.y() + length(availableScreenRect.height()) }; } else { position = {availableScreenRect.right() - m_view->width() + 1, availableScreenRect.y()}; } break; case Plasma::Types::LeftEdge: if (m_view->behaveAsPlasmaPanel() && !m_view->mask().isNull()) { position = {availableScreenRect.x(), availableScreenRect.y() + length(availableScreenRect.height())}; } else { position = {availableScreenRect.x(), availableScreenRect.y()}; } break; default: qWarning() << "wrong location, couldn't update the panel position" << m_view->location(); } m_validGeometry.setTopLeft(position); m_view->setPosition(position); if (m_view->surface()) { m_view->surface()->setPosition(position); } } void Positioner::resizeWindow(QRect availableScreenRect) { QSize screenSize = m_view->screen()->size(); QSize size = (m_view->formFactor() == Plasma::Types::Vertical) ? QSize(m_view->maxThickness(), availableScreenRect.height()) : QSize(screenSize.width(), m_view->maxThickness()); if (m_view->formFactor() == Plasma::Types::Vertical) { //qDebug() << "MAXIMUM RECT :: " << maximumRect << " - AVAILABLE RECT :: " << availableRect; if (m_view->behaveAsPlasmaPanel()) { size.setWidth(m_view->normalThickness()); size.setHeight(static_cast(m_view->maxLength() * availableScreenRect.height())); } } else { if (m_view->behaveAsPlasmaPanel()) { size.setWidth(static_cast(m_view->maxLength() * screenSize.width())); size.setHeight(m_view->normalThickness()); } } m_validGeometry.setSize(size); m_view->setMinimumSize(size); m_view->setMaximumSize(size); m_view->resize(size); if (m_view->formFactor() == Plasma::Types::Horizontal && m_view->corona()) { emit m_view->corona()->availableScreenRectChanged(); } } void Positioner::updateFormFactor() { if (!m_view->containment()) return; switch (m_view->location()) { case Plasma::Types::TopEdge: case Plasma::Types::BottomEdge: m_view->containment()->setFormFactor(Plasma::Types::Horizontal); break; case Plasma::Types::LeftEdge: case Plasma::Types::RightEdge: m_view->containment()->setFormFactor(Plasma::Types::Vertical); break; default: qWarning() << "wrong location, couldn't update the panel position" << m_view->location(); } } void Positioner::initSignalingForLocationChangeSliding() { //! signals to handle the sliding-in/out during location changes connect(this, &Positioner::hideDockDuringLocationChangeStarted, this, &Positioner::onHideWindowsForSlidingOut); connect(m_view, &DockView::locationChanged, this, [&]() { if (m_goToLocation != Plasma::Types::Floating) { m_goToLocation = Plasma::Types::Floating; QTimer::singleShot(100, [this]() { m_view->setBlockAnimations(false); emit showDockAfterLocationChangeFinished(); m_view->showSettingsWindow(); if (m_view->managedLayout()) { m_view->managedLayout()->syncDockViewsToScreens(); } }); } }); //! signals to handle the sliding-in/out during screen changes connect(this, &Positioner::hideDockDuringScreenChangeStarted, this, &Positioner::onHideWindowsForSlidingOut); connect(m_view, &DockView::currentScreenChanged, this, [&]() { if (m_goToScreen) { m_goToScreen = nullptr; QTimer::singleShot(100, [this]() { m_view->setBlockAnimations(false); emit showDockAfterScreenChangeFinished(); m_view->showSettingsWindow(); if (m_view->managedLayout()) { m_view->managedLayout()->syncDockViewsToScreens(); } }); } }); //! signals to handle the sliding-in/out during moving to another layout connect(this, &Positioner::hideDockDuringMovingToLayoutStarted, this, &Positioner::onHideWindowsForSlidingOut); connect(m_view, &DockView::managedLayoutChanged, this, [&]() { if (!m_moveToLayout.isEmpty() && m_view->managedLayout()) { m_moveToLayout = ""; QTimer::singleShot(100, [this]() { m_view->setBlockAnimations(false); emit showDockAfterMovingToLayoutFinished(); m_view->showSettingsWindow(); }); } }); //! ---- both cases ---- !// //! this is used for both location and screen change cases, this signal //! is send when the sliding-out animation has finished connect(this, &Positioner::hideDockDuringLocationChangeFinished, this, [&]() { m_view->setBlockAnimations(true); if (m_goToLocation != Plasma::Types::Floating) { m_view->setLocation(m_goToLocation); } else if (m_goToScreen) { setScreenToFollow(m_goToScreen); } else if (!m_moveToLayout.isEmpty()) { m_view->moveToLayout(m_moveToLayout); } }); } bool Positioner::inLocationChangeAnimation() { return ((m_goToLocation != Plasma::Types::Floating) || (m_moveToLayout != "") || m_goToScreen); } void Positioner::hideDockDuringLocationChange(int goToLocation) { m_goToLocation = static_cast(goToLocation); emit hideDockDuringLocationChangeStarted(); } void Positioner::hideDockDuringMovingToLayout(QString layoutName) { m_moveToLayout = layoutName; emit hideDockDuringMovingToLayoutStarted(); } } } diff --git a/app/dockcorona.cpp b/app/dockcorona.cpp index 97890d2f..960d3d13 100644 --- a/app/dockcorona.cpp +++ b/app/dockcorona.cpp @@ -1,956 +1,956 @@ /* * 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 "dockcorona.h" #include "abstractwindowinterface.h" #include "alternativeshelper.h" #include "globalshortcuts.h" #include "importer.h" #include "launcherssignals.h" #include "layoutmanager.h" #include "plasmathemeextended.h" #include "screenpool.h" #include "universalsettings.h" #include "waylandinterface.h" #include "xwindowinterface.h" #include "dock/dockview.h" #include "packageplugins/shell/dockpackage.h" //dbus adaptor #include "lattedockadaptor.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Latte { DockCorona::DockCorona(bool defaultLayoutOnStartup, QString layoutNameOnStartUp, int userSetMemoryUsage, QObject *parent) : Plasma::Corona(parent), m_defaultLayoutOnStartup(defaultLayoutOnStartup), m_userSetMemoryUsage(userSetMemoryUsage), m_layoutNameOnStartUp(layoutNameOnStartUp), m_activityConsumer(new KActivities::Consumer(this)), m_screenPool(new ScreenPool(KSharedConfig::openConfig(), this)), m_globalShortcuts(new GlobalShortcuts(this)), m_universalSettings(new UniversalSettings(KSharedConfig::openConfig(), this)), m_themeExtended(new PlasmaThemeExtended(KSharedConfig::openConfig(), this)), m_layoutManager(new LayoutManager(this)) { //! create the window manager if (KWindowSystem::isPlatformWayland()) { m_wm = new WaylandInterface(this); } else { m_wm = new XWindowInterface(this); } setupWaylandIntegration(); KPackage::Package package(new DockPackage(this)); m_screenPool->load(); if (!package.isValid()) { qWarning() << staticMetaObject.className() << "the package" << package.metadata().rawData() << "is invalid!"; return; } else { qDebug() << staticMetaObject.className() << "the package" << package.metadata().rawData() << "is valid!"; } setKPackage(package); //! universal settings / extendedtheme must be loaded after the package has been set m_universalSettings->load(); m_themeExtended->load(); qmlRegisterTypes(); if (m_activityConsumer && (m_activityConsumer->serviceStatus() == KActivities::Consumer::Running)) { load(); } connect(m_activityConsumer, &KActivities::Consumer::serviceStatusChanged, this, &DockCorona::load); m_docksScreenSyncTimer.setSingleShot(true); m_docksScreenSyncTimer.setInterval(m_universalSettings->screenTrackerInterval()); connect(&m_docksScreenSyncTimer, &QTimer::timeout, this, &DockCorona::syncDockViewsToScreens); connect(m_universalSettings, &UniversalSettings::screenTrackerIntervalChanged, this, [this]() { m_docksScreenSyncTimer.setInterval(m_universalSettings->screenTrackerInterval()); }); //! Dbus adaptor initialization new LatteDockAdaptor(this); QDBusConnection dbus = QDBusConnection::sessionBus(); dbus.registerObject(QStringLiteral("/Latte"), this); } DockCorona::~DockCorona() { //! BEGIN: Give the time to slide-out docks when closing m_layoutManager->hideAllDocks(); //! Don't delay the destruction under wayland in any case //! because it creates a crash with kwin effects //! https://bugs.kde.org/show_bug.cgi?id=392890 if (!KWindowSystem::isPlatformWayland()) { QTimer::singleShot(400, [this]() { m_quitTimedEnded = true; }); while (!m_quitTimedEnded) { QGuiApplication::processEvents(QEventLoop::AllEvents, 50); } } //! END: slide-out docks when closing m_docksScreenSyncTimer.stop(); if (m_layoutManager->memoryUsage() == Dock::SingleLayout) { cleanConfig(); } qDebug() << "Latte Corona - unload: containments ..."; m_layoutManager->unload(); m_wm->deleteLater(); m_globalShortcuts->deleteLater(); m_layoutManager->deleteLater(); m_screenPool->deleteLater(); m_universalSettings->deleteLater(); m_themeExtended->deleteLater(); disconnect(m_activityConsumer, &KActivities::Consumer::serviceStatusChanged, this, &DockCorona::load); delete m_activityConsumer; qDebug() << "Latte Corona - deleted..."; } void DockCorona::load() { if (m_activityConsumer && (m_activityConsumer->serviceStatus() == KActivities::Consumer::Running) && m_activitiesStarting) { disconnect(m_activityConsumer, &KActivities::Consumer::serviceStatusChanged, this, &DockCorona::load); m_layoutManager->load(); m_activitiesStarting = false; connect(qGuiApp, &QGuiApplication::primaryScreenChanged, this, &DockCorona::primaryOutputChanged, Qt::UniqueConnection); connect(QApplication::desktop(), &QDesktopWidget::screenCountChanged, this, &DockCorona::screenCountChanged); connect(m_screenPool, &ScreenPool::primaryPoolChanged, this, &DockCorona::screenCountChanged); QString assignedLayout = m_layoutManager->shouldSwitchToLayout(m_activityConsumer->currentActivity()); QString loadLayoutName = ""; if (!m_defaultLayoutOnStartup && m_layoutNameOnStartUp.isEmpty()) { if (!assignedLayout.isEmpty() && assignedLayout != m_universalSettings->currentLayoutName()) { loadLayoutName = assignedLayout; } else { loadLayoutName = m_universalSettings->currentLayoutName(); } if (!m_layoutManager->layoutExists(loadLayoutName)) { loadLayoutName = m_layoutManager->defaultLayoutName(); m_layoutManager->importDefaultLayout(false); } } else if (m_defaultLayoutOnStartup) { loadLayoutName = m_layoutManager->importer()->uniqueLayoutName(m_layoutManager->defaultLayoutName()); m_layoutManager->importDefaultLayout(true); } else { loadLayoutName = m_layoutNameOnStartUp; } if (m_userSetMemoryUsage != -1 && !KWindowSystem::isPlatformWayland()) { Dock::LayoutsMemoryUsage usage = static_cast(m_userSetMemoryUsage); m_universalSettings->setLayoutsMemoryUsage(usage); } if (KWindowSystem::isPlatformWayland()) { m_universalSettings->setLayoutsMemoryUsage(Dock::SingleLayout); } m_layoutManager->loadLayoutOnStartup(loadLayoutName); //! load screens signals such screenGeometryChanged in order to support //! plasmoid.screenGeometry properly for (QScreen *screen : qGuiApp->screens()) { addOutput(screen); } connect(qGuiApp, &QGuiApplication::screenAdded, this, &DockCorona::addOutput, Qt::UniqueConnection); } } void DockCorona::unload() { qDebug() << "unload: removing containments..."; while (!containments().isEmpty()) { //deleting a containment will remove it from the list due to QObject::destroyed connect in Corona //this form doesn't crash, while qDeleteAll(containments()) does delete containments().first(); } } void DockCorona::setupWaylandIntegration() { if (!KWindowSystem::isPlatformWayland()) { return; } using namespace KWayland::Client; auto connection = ConnectionThread::fromApplication(this); if (!connection) { return; } Registry *registry{new Registry(this)}; registry->create(connection); connect(registry, &Registry::plasmaShellAnnounced, this , [this, registry](quint32 name, quint32 version) { m_waylandDockCorona = registry->createPlasmaShell(name, version, this); }); QObject::connect(registry, &KWayland::Client::Registry::plasmaWindowManagementAnnounced, [this, registry](quint32 name, quint32 version) { KWayland::Client::PlasmaWindowManagement *pwm = registry->createPlasmaWindowManagement(name, version, this); WaylandInterface *wI = qobject_cast(m_wm); if (wI) { wI->initWindowManagement(pwm); } }); registry->setup(); connection->roundtrip(); } KWayland::Client::PlasmaShell *DockCorona::waylandDockCoronaInterface() const { return m_waylandDockCorona; } void DockCorona::cleanConfig() { auto containmentsEntries = config()->group("Containments"); bool changed = false; foreach (auto cId, containmentsEntries.groupList()) { if (!containmentExists(cId.toUInt())) { //cleanup obsolete containments containmentsEntries.group(cId).deleteGroup(); changed = true; qDebug() << "obsolete containment configuration deleted:" << cId; } else { //cleanup obsolete applets of running containments auto appletsEntries = containmentsEntries.group(cId).group("Applets"); foreach (auto appletId, appletsEntries.groupList()) { if (!appletExists(cId.toUInt(), appletId.toUInt())) { appletsEntries.group(appletId).deleteGroup(); changed = true; qDebug() << "obsolete applet configuration deleted:" << appletId; } } } } if (changed) { config()->sync(); qDebug() << "configuration file cleaned..."; } } bool DockCorona::containmentExists(uint id) const { foreach (auto containment, containments()) { if (id == containment->id()) { return true; } } return false; } bool DockCorona::appletExists(uint containmentId, uint appletId) const { Plasma::Containment *containment = nullptr; foreach (auto cont, containments()) { if (containmentId == cont->id()) { containment = cont; break; } } if (!containment) { return false; } foreach (auto applet, containment->applets()) { if (applet->id() == appletId) { return true; } } return false; } KActivities::Consumer *DockCorona::activitiesConsumer() const { return m_activityConsumer; } ScreenPool *DockCorona::screenPool() const { return m_screenPool; } UniversalSettings *DockCorona::universalSettings() const { return m_universalSettings; } LayoutManager *DockCorona::layoutManager() const { return m_layoutManager; } AbstractWindowInterface *DockCorona::wm() const { return m_wm; } PlasmaThemeExtended *DockCorona::themeExtended() const { return m_themeExtended; } int DockCorona::numScreens() const { return qGuiApp->screens().count(); } QRect DockCorona::screenGeometry(int id) const { const auto screens = qGuiApp->screens(); const QScreen *screen{qGuiApp->primaryScreen()}; QString screenName; if (m_screenPool->knownIds().contains(id)) screenName = m_screenPool->connector(id); foreach (auto scr, screens) { if (scr->name() == screenName) { screen = scr; break; } } return screen->geometry(); } QRegion DockCorona::availableScreenRegion(int id) const { return availableScreenRegionWithCriteria(id); } QRegion DockCorona::availableScreenRegionWithCriteria(int id, QString forLayout) const { const auto screens = qGuiApp->screens(); const QScreen *screen{qGuiApp->primaryScreen()}; QString screenName; if (m_screenPool->knownIds().contains(id)) screenName = m_screenPool->connector(id); foreach (auto scr, screens) { if (scr->name() == screenName) { screen = scr; break; } } if (!screen) return QRegion(); QHash *views; if (forLayout.isEmpty()) { views = m_layoutManager->currentDockViews(); } else { views = m_layoutManager->layoutDockViews(forLayout); } QRegion available(screen->geometry()); if (views) { for (const auto *view : *views) { if (view && view->containment() && view->screen() == screen && view->visibility() && (view->visibility()->mode() != Latte::Dock::AutoHide)) { - int realThickness = view->normalThickness() - view->shadow(); + int realThickness = view->normalThickness() - view->effects()->innerShadow(); // Usually availableScreenRect is used by the desktop, // but Latte don't have desktop, then here just // need calculate available space for top and bottom location, // because the left and right are those who dodge others docks switch (view->location()) { case Plasma::Types::TopEdge: if (view->behaveAsPlasmaPanel()) { available -= view->geometry(); } else { QRect realGeometry; int realWidth = view->maxLength() * view->width(); switch (view->alignment()) { case Latte::Dock::Left: realGeometry = QRect(view->x(), view->y(), realWidth, realThickness); break; case Latte::Dock::Center: case Latte::Dock::Justify: realGeometry = QRect(qMax(view->geometry().x(), view->geometry().center().x() - realWidth / 2), view->y(), realWidth, realThickness); break; case Latte::Dock::Right: realGeometry = QRect(view->geometry().right() - realWidth + 1, view->y(), realWidth, realThickness); break; } available -= realGeometry; } break; case Plasma::Types::BottomEdge: if (view->behaveAsPlasmaPanel()) { available -= view->geometry(); } else { QRect realGeometry; int realWidth = view->maxLength() * view->width(); int realY = view->geometry().bottom() - realThickness + 1; switch (view->alignment()) { case Latte::Dock::Left: realGeometry = QRect(view->x(), realY, realWidth, realThickness); break; case Latte::Dock::Center: case Latte::Dock::Justify: realGeometry = QRect(qMax(view->geometry().x(), view->geometry().center().x() - realWidth / 2), realY, realWidth, realThickness); break; case Latte::Dock::Right: realGeometry = QRect(view->geometry().right() - realWidth + 1, realY, realWidth, realThickness); break; } available -= realGeometry; } break; default: //! bypass clang warnings break; } } } } /*qDebug() << "::::: FREE AREAS :::::"; for (int i = 0; i < available.rectCount(); ++i) { qDebug() << available.rects().at(i); } qDebug() << "::::: END OF FREE AREAS :::::";*/ return available; } QRect DockCorona::availableScreenRect(int id) const { return availableScreenRectWithCriteria(id); } QRect DockCorona::availableScreenRectWithCriteria(int id, QList modes, QList edges) const { const auto screens = qGuiApp->screens(); const QScreen *screen{qGuiApp->primaryScreen()}; if (m_screenPool->knownIds().contains(id)) { QString scrName = m_screenPool->connector(id); foreach (auto scr, screens) { if (scr->name() == scrName) { screen = scr; break; } } } if (!screen) return {}; bool allModes = modes.isEmpty(); bool allEdges = edges.isEmpty(); auto available = screen->geometry(); QHash *views = m_layoutManager->currentDockViews(); if (views) { for (const auto *view : *views) { if (view && view->containment() && view->screen() == screen && ((allEdges || edges.contains(view->location())) && (allModes || (view->visibility() && modes.contains(view->visibility()->mode()))))) { auto dockRect = view->absGeometry(); // Usually availableScreenRect is used by the desktop, // but Latte don't have desktop, then here just // need calculate available space for top and bottom location, // because the left and right are those who dodge others docks switch (view->location()) { case Plasma::Types::TopEdge: available.setTop(dockRect.bottom() + 1); break; case Plasma::Types::BottomEdge: available.setBottom(dockRect.top() - 1); break; case Plasma::Types::LeftEdge: available.setLeft(dockRect.right() + 1); break; case Plasma::Types::RightEdge: available.setRight(dockRect.left() - 1); break; default: //! bypass clang warnings break; } } } } return available; } void DockCorona::addOutput(QScreen *screen) { Q_ASSERT(screen); int id = m_screenPool->id(screen->name()); if (id == -1) { int newId = m_screenPool->firstAvailableId(); m_screenPool->insertScreenMapping(newId, screen->name()); } connect(screen, &QScreen::geometryChanged, this, [ = ]() { const int id = m_screenPool->id(screen->name()); if (id >= 0) { emit screenGeometryChanged(id); emit availableScreenRegionChanged(); emit availableScreenRectChanged(); } }); emit availableScreenRectChanged(); emit screenAdded(m_screenPool->id(screen->name())); } void DockCorona::primaryOutputChanged() { m_docksScreenSyncTimer.start(); } void DockCorona::screenRemoved(QScreen *screen) { Q_ASSERT(screen); } void DockCorona::screenCountChanged() { m_docksScreenSyncTimer.start(); } //! the central functions that updates loading/unloading dockviews //! concerning screen changed (for multi-screen setups mainly) void DockCorona::syncDockViewsToScreens() { m_layoutManager->syncDockViewsToScreens(); } int DockCorona::primaryScreenId() const { return m_screenPool->id(qGuiApp->primaryScreen()->name()); } void DockCorona::closeApplication() { //! this code must be called asynchronously because it is called //! also from qml (Settings window). QTimer::singleShot(5, [this]() { m_layoutManager->hideLatteSettingsDialog(); m_layoutManager->hideAllDocks(); }); //! give the time for the docks to hide themselves QTimer::singleShot(500, [this]() { qGuiApp->quit(); }); } void DockCorona::aboutApplication() { if (aboutDialog) { aboutDialog->hide(); aboutDialog->deleteLater(); } aboutDialog = new KAboutApplicationDialog(KAboutData::applicationData()); connect(aboutDialog.data(), &QDialog::finished, aboutDialog.data(), &QObject::deleteLater); m_wm->skipTaskBar(*aboutDialog); m_wm->setKeepAbove(*aboutDialog, true); aboutDialog->show(); } int DockCorona::screenForContainment(const Plasma::Containment *containment) const { //FIXME: indexOf is not a proper way to support multi-screen // as for environment to environment the indexes change // also there is the following issue triggered // from dockView adaptToScreen() // // in a multi-screen environment that // primary screen is not set to 0 it was // created an endless showing loop at // startup (catch-up race) between // screen:0 and primaryScreen //case in which this containment is child of an applet, hello systray :) if (Plasma::Applet *parentApplet = qobject_cast(containment->parent())) { if (Plasma::Containment *cont = parentApplet->containment()) { return screenForContainment(cont); } else { return -1; } } QHash *views = m_layoutManager->currentDockViews(); //if the panel views already exist, base upon them DockView *view = views ? views->value(containment) : nullptr; if (view && view->screen()) { return m_screenPool->id(view->screen()->name()); } //Failed? fallback on lastScreen() //lastScreen() is the correct screen for panels //It is also correct for desktops *that have the correct activity()* //a containment with lastScreen() == 0 but another activity, //won't be associated to a screen // qDebug() << "ShellCorona screenForContainment: " << containment << " Last screen is " << containment->lastScreen(); for (auto screen : qGuiApp->screens()) { // containment->lastScreen() == m_screenPool->id(screen->name()) to check if the lastScreen refers to a screen that exists/it's known if (containment->lastScreen() == m_screenPool->id(screen->name()) && (containment->activity() == m_activityConsumer->currentActivity() || containment->containmentType() == Plasma::Types::PanelContainment || containment->containmentType() == Plasma::Types::CustomPanelContainment)) { return containment->lastScreen(); } } return -1; } void DockCorona::showAlternativesForApplet(Plasma::Applet *applet) { const QString alternativesQML = kPackage().filePath("appletalternativesui"); if (alternativesQML.isEmpty()) { return; } QHash *views = m_layoutManager->currentDockViews(); DockView *dockView = (*views)[applet->containment()]; KDeclarative::QmlObject *qmlObj{nullptr}; if (dockView) { dockView->setAlternativesIsShown(true); qmlObj = new KDeclarative::QmlObject(dockView); } else { qmlObj = new KDeclarative::QmlObject(this); } qmlObj->setInitializationDelayed(true); qmlObj->setSource(QUrl::fromLocalFile(alternativesQML)); AlternativesHelper *helper = new AlternativesHelper(applet, qmlObj); qmlObj->rootContext()->setContextProperty(QStringLiteral("alternativesHelper"), helper); m_alternativesObjects << qmlObj; qmlObj->completeInitialization(); //! Alternative dialog signals connect(helper, &QObject::destroyed, this, [dockView]() { dockView->setAlternativesIsShown(false); }); connect(qmlObj->rootObject(), SIGNAL(visibleChanged(bool)), this, SLOT(alternativesVisibilityChanged(bool))); connect(applet, &Plasma::Applet::destroyedChanged, this, [this, qmlObj](bool destroyed) { if (!destroyed) { return; } QMutableListIterator it(m_alternativesObjects); while (it.hasNext()) { KDeclarative::QmlObject *obj = it.next(); if (obj == qmlObj) { it.remove(); obj->deleteLater(); } } }); } void DockCorona::alternativesVisibilityChanged(bool visible) { if (visible) { return; } QObject *root = sender(); QMutableListIterator it(m_alternativesObjects); while (it.hasNext()) { KDeclarative::QmlObject *obj = it.next(); if (obj->rootObject() == root) { it.remove(); obj->deleteLater(); } } } void DockCorona::loadDefaultLayout() { qDebug() << "loading default layout"; //! Settting mutable for create a containment setImmutability(Plasma::Types::Mutable); QVariantList args; auto defaultContainment = createContainmentDelayed("org.kde.latte.containment", args); defaultContainment->setContainmentType(Plasma::Types::PanelContainment); defaultContainment->init(); if (!defaultContainment || !defaultContainment->kPackage().isValid()) { qWarning() << "the requested containment plugin can not be located or loaded"; return; } auto config = defaultContainment->config(); defaultContainment->restore(config); using Plasma::Types; QList edges{Types::BottomEdge, Types::LeftEdge, Types::TopEdge, Types::RightEdge}; Layout *currentLayout = m_layoutManager->activeLayout(m_layoutManager->currentLayoutName()); if (currentLayout) { edges = currentLayout->freeEdges(defaultContainment->screen()); } if ((edges.count() > 0)) { defaultContainment->setLocation(edges.at(0)); } else { defaultContainment->setLocation(Plasma::Types::BottomEdge); } if (m_layoutManager->memoryUsage() == Dock::MultipleLayouts) { config.writeEntry("layoutId", m_layoutManager->currentLayoutName()); } defaultContainment->updateConstraints(Plasma::Types::StartupCompletedConstraint); defaultContainment->save(config); requestConfigSync(); defaultContainment->flushPendingConstraintsEvents(); emit containmentAdded(defaultContainment); emit containmentCreated(defaultContainment); //m_layoutManager->addDock(defaultContainment); defaultContainment->createApplet(QStringLiteral("org.kde.latte.plasmoid")); defaultContainment->createApplet(QStringLiteral("org.kde.plasma.analogclock")); } QStringList DockCorona::containmentsIds() { QStringList ids; foreach (auto containment, containments()) { ids << QString::number(containment->id()); } return ids; } QStringList DockCorona::appletsIds() { QStringList ids; foreach (auto containment, containments()) { auto applets = containment->config().group("Applets"); ids << applets.groupList(); } return ids; } //! Activate launcher menu through dbus interface void DockCorona::activateLauncherMenu() { m_globalShortcuts->activateLauncherMenu(); } void DockCorona::windowColorScheme(QString windowIdAndScheme) { int firstSlash = windowIdAndScheme.indexOf("-"); QString windowIdStr = windowIdAndScheme.mid(0, firstSlash); QString schemeStr = windowIdAndScheme.mid(firstSlash + 1); m_wm->setColorSchemeForWindow(windowIdStr, schemeStr); } //! update badge for specific dock item void DockCorona::updateDockItemBadge(QString identifier, QString value) { m_globalShortcuts->updateDockItemBadge(identifier, value); } void DockCorona::switchToLayout(QString layout) { m_layoutManager->switchToLayout(layout); } void DockCorona::showSettingsWindow(int page) { Dock::LatteConfigPage p = Dock::LayoutPage; if (page >= Dock::LayoutPage && page <= Dock::PreferencesPage) { p = static_cast(page); } m_layoutManager->showLatteSettingsDialog(p); } QStringList DockCorona::contextMenuData() { QStringList data; data << QString::number((int)m_layoutManager->memoryUsage()); data << m_layoutManager->currentLayoutName(); foreach (auto layoutName, m_layoutManager->menuLayouts()) { if (m_layoutManager->activeLayout(layoutName)) { data << QString("1," + layoutName); } else { data << QString("0," + layoutName); } } return data; } inline void DockCorona::qmlRegisterTypes() const { qmlRegisterType(); } } diff --git a/containment/package/contents/ui/EditModeVisual.qml b/containment/package/contents/ui/EditModeVisual.qml index 8d64b4e0..810d9d5a 100644 --- a/containment/package/contents/ui/EditModeVisual.qml +++ b/containment/package/contents/ui/EditModeVisual.qml @@ -1,371 +1,359 @@ /* * 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.1 import QtGraphicalEffects 1.0 import org.kde.plasma.plasmoid 2.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.latte 0.1 as Latte Item{ id: editVisual width: root.isHorizontal ? (dock ? dock.width : root.width) : visibilityManager.thicknessNormalOriginal + theme.defaultFont.pixelSize height: root.isVertical ? (dock ? dock.height : root.height) : visibilityManager.thicknessNormalOriginal + theme.defaultFont.pixelSize opacity: 0 property int speed: Latte.WindowSystem.compositingActive ? root.durationTime*2.8*units.longDuration : 10 property int thickness: visibilityManager.thicknessNormalOriginalValue + root.editShadow property int rootThickness: visibilityManager.thicknessZoomOriginal + root.editShadow - theme.defaultFont.pixelSize property int editLength: root.isHorizontal ? (root.behaveAsPlasmaPanel ? root.width - root.maxIconSize/4 : root.width)://root.maxLength) : (root.behaveAsPlasmaPanel ? root.height - root.maxIconSize/4 : root.height) property real editStateOpacity: 0.95 //root.behaveAsPlasmaPanel ? 0.5 : 0.95// root.blurEnabled ? 0.8 : 0.9 property bool animationSent: false property bool farEdge: (plasmoid.location===PlasmaCore.Types.BottomEdge) || (plasmoid.location===PlasmaCore.Types.RightEdge) property bool editAnimationEnded: false property bool plasmaEditMode: plasmoid.userConfiguring property bool inEditMode: false property rect efGeometry property string layoutColor: root.dockManagedLayout ? root.dockManagedLayout.color : "blue" Item{ id: shadow width: root.isHorizontal ? imageTiler.width + 2*root.editShadow : root.editShadow height: root.isHorizontal ? root.editShadow : imageTiler.height + 2*root.editShadow clip: true visible: !editTransition.running EditShadow{ id: editShadow } states: [ ///topShadow State { name: "topShadow" when: (plasmoid.location === PlasmaCore.Types.BottomEdge) AnchorChanges { target: shadow anchors{ top:undefined; bottom:imageTiler.top; left:undefined; right:undefined; horizontalCenter:imageTiler.horizontalCenter; verticalCenter:undefined} } AnchorChanges { target: editShadow anchors{ top:parent.top; bottom:undefined; left:parent.left; right:undefined; horizontalCenter:parent.horizontalCenter; verticalCenter:parent.undefined} } PropertyChanges{ target: editShadow anchors{ leftMargin: 0; rightMargin:0; topMargin:root.editShadow; bottomMargin:0} } }, ///bottomShadow State { name: "bottomShadow" when: (plasmoid.location === PlasmaCore.Types.TopEdge) AnchorChanges { target: shadow anchors{ top:imageTiler.bottom; bottom:undefined; left:undefined; right:undefined; horizontalCenter:imageTiler.horizontalCenter; verticalCenter:undefined} } AnchorChanges { target: editShadow anchors{ top:undefined; bottom:parent.bottom; left:undefined; right:undefined; horizontalCenter:parent.horizontalCenter; verticalCenter:undefined} } PropertyChanges{ target: editShadow anchors{ leftMargin: 0; rightMargin:0; topMargin:0; bottomMargin:root.editShadow} } }, ///leftShadow State { name: "leftShadow" when: (plasmoid.location === PlasmaCore.Types.RightEdge) AnchorChanges { target: shadow anchors{ top:undefined; bottom:undefined; left:undefined; right:imageTiler.left; horizontalCenter:undefined; verticalCenter:imageTiler.verticalCenter} } AnchorChanges { target: editShadow anchors{ top:undefined; bottom:undefined; left:parent.left; right:undefined; horizontalCenter:undefined; verticalCenter:undefined} } PropertyChanges{ target: editShadow anchors{ leftMargin: root.editShadow; rightMargin:0; topMargin:0; bottomMargin:0} } }, ///rightShadow State { name: "rightShadow" when: (plasmoid.location === PlasmaCore.Types.LeftEdge) AnchorChanges { target: shadow anchors{ top:undefined; bottom:undefined; left:imageTiler.right; right:undefined; horizontalCenter:undefined; verticalCenter:imageTiler.verticalCenter} } AnchorChanges { target: editShadow anchors{ top:undefined; bottom:undefined; left:undefined; right:parent.right; horizontalCenter:undefined; verticalCenter:undefined} } PropertyChanges{ target: editShadow anchors{ leftMargin: 0; rightMargin:root.editShadow; topMargin:0; bottomMargin:0} } } ] } Image{ id: imageTiler anchors.centerIn: parent width: parent.width height: parent.height opacity: editVisual.editStateOpacity fillMode: Image.Tile source: hasBackground ? dock.managedLayout.background : "../icons/"+editVisual.layoutColor+"print.jpg" readonly property bool hasBackground: (dock && dock.managedLayout && dock.managedLayout.background.startsWith("/")) ? true : false } Connections{ target: plasmoid onLocationChanged: initializeEditPosition(); } onRootThicknessChanged: { initializeEditPosition(); } onThicknessChanged: { initializeEditPosition(); } - onEditAnimationEndedChanged: { - if (!dock) { - return; - } - - if (editAnimationEnded && !root.behaveAsPlasmaPanel) { - dock.shadow = root.editShadow; - } else { - dock.shadow = root.panelShadow; - } - } - onXChanged: updateEffectsArea(); onYChanged: updateEffectsArea(); onWidthChanged: { /*if (root.isHorizontal) { initializeEditPosition(); }*/ updateEffectsArea(); } onHeightChanged: { /* if (root.isVertical) { initializeEditPosition(); }*/ updateEffectsArea(); } function updateEffectsArea(){ if (!dock || state !== "edit" || !editAnimationEnded) return; var rootGeometry = mapToItem(root, 0, 0); efGeometry.x = rootGeometry.x; efGeometry.y = rootGeometry.y; efGeometry.width = width; efGeometry.height = height; dock.effects.rect = efGeometry; } function initializeNormalPosition() { if (plasmoid.location === PlasmaCore.Types.BottomEdge) { y = rootThickness; x = 0; } else if (plasmoid.location === PlasmaCore.Types.RightEdge) { x = rootThickness; y = 0; } else if (plasmoid.location === PlasmaCore.Types.LeftEdge) { x = -editVisual.thickness; y = 0; } else if (plasmoid.location === PlasmaCore.Types.TopEdge) { y = -editVisual.thickness; x = 0; } } function initializeEditPosition() { if (root.editMode) { if (plasmoid.location === PlasmaCore.Types.LeftEdge){ x = 0; y = 0; } else if (plasmoid.location === PlasmaCore.Types.TopEdge) { x = 0; y = 0; } else if (plasmoid.location === PlasmaCore.Types.BottomEdge) { x = 0; y = rootThickness - thickness; } else if (plasmoid.location === PlasmaCore.Types.RightEdge) { x = rootThickness - thickness; y = 0; } } } //////////// States //////////////////// states: [ State{ name: "*" when: !plasmaEditMode }, State{ name: "edit" when: plasmaEditMode } ] transitions: [ Transition{ id: editTransition from: "*" to: "edit" SequentialAnimation{ id:normalAnimationTransition ScriptAction{ script:{ editVisual.inEditMode = true; editVisual.opacity = 0 editVisual.editAnimationEnded = false; initializeNormalPosition(); if(!animationSent) { animationSent = true; root.slotAnimationsNeedLength(1); } } } ParallelAnimation{ PropertyAnimation { target: editVisual property: "opacity" to: 1 duration: editVisual.speed / 2 easing.type: Easing.OutQuad } PropertyAnimation { target: editVisual property: root.isHorizontal ? "y" : "x" to: editVisual.farEdge ? editVisual.rootThickness - editVisual.thickness : 0 duration: editVisual.speed easing.type: Easing.OutQuad } } ScriptAction{ script:{ editVisual.editAnimationEnded = true; updateEffectsArea(); updateAutomaticIconSize(); visibilityManager.updateMaskArea(); } } } }, Transition{ from: "edit" to: "*" SequentialAnimation{ ScriptAction{ script: { //! remove kwin effects when starting the animation dock.effects.rect = Qt.rect(-1, -1, 0, 0); } } ParallelAnimation{ PropertyAnimation { target: editVisual property: root.isHorizontal ? "y" : "x" to: editVisual.farEdge ? editVisual.rootThickness : -editVisual.thickness duration: editVisual.speed easing.type: Easing.InQuad } PropertyAnimation { target: editVisual property: "opacity" to: 0 duration: editVisual.speed easing.type: Easing.InQuad } } ScriptAction{ script:{ editVisual.inEditMode = false; editVisual.editAnimationEnded = false; if (editVisual.animationSent) { root.slotAnimationsNeedLength(-1); editVisual.animationSent = false; } if (visibilityManager.inTempHiding) { visibilityManager.sendHideDockDuringLocationChangeFinished(); } } } } } ] } diff --git a/containment/package/contents/ui/VisibilityManager.qml b/containment/package/contents/ui/VisibilityManager.qml index 5cbcd9b0..8830e001 100644 --- a/containment/package/contents/ui/VisibilityManager.qml +++ b/containment/package/contents/ui/VisibilityManager.qml @@ -1,657 +1,663 @@ /* * 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.1 import QtQuick.Window 2.2 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.plasmoid 2.0 import org.kde.latte 0.1 as Latte Item{ id: manager anchors.fill: parent property QtObject window property bool debugMagager: Qt.application.arguments.indexOf("--mask") >= 0 property bool blockUpdateMask: false property bool inForceHiding: false //is used when the docks are forced in hiding e.g. when changing layouts property bool normalState : false // this is being set from updateMaskArea property bool previousNormalState : false // this is only for debugging purposes property bool panelIsBiggerFromIconSize: root.useThemePanel && (root.themePanelSize >= root.iconSize) property int animationSpeed: Latte.WindowSystem.compositingActive ? root.durationTime * 1.2 * units.longDuration : 0 property bool inSlidingIn: false //necessary because of its init structure property alias inSlidingOut: slidingAnimationAutoHiddenOut.running property bool inTempHiding: false property int length: root.isVertical ? Screen.height : Screen.width //screenGeometry.height : screenGeometry.width property int slidingOutToPos: ((plasmoid.location===PlasmaCore.Types.LeftEdge)||(plasmoid.location===PlasmaCore.Types.TopEdge)) ? -thicknessNormal : thicknessNormal; property int statesLineSizeOriginal: root.latteApplet ? Math.ceil( root.maxIconSize/13 ) : 0 property int thickReverseAndGlowExtraSize: (root.reverseLinesPosition && root.showGlow && !behaveAsPlasmaPanel) ? 2*statesLineSize : 0; property int thickReverseAndGlowExtraSizeOriginal: Math.ceil(2*root.maxIconSize/13 ) property int thicknessAutoHidden: Latte.WindowSystem.compositingActive ? 2 : 1 property int thicknessMid: root.statesLineSize + (1 + (0.65 * (root.zoomFactor-1)))*(root.iconSize+root.thickMargin + thickReverseAndGlowExtraSize) //needed in some animations property int thicknessNormal: Math.max(root.statesLineSize + root.iconSize + root.thickMargin + thickReverseAndGlowExtraSize +1, root.realPanelSize + root.panelShadow) property int thicknessZoom: root.statesLineSize + ((root.iconSize+root.thickMargin + thickReverseAndGlowExtraSize) * root.zoomFactor) + 2 //it is used to keep thickness solid e.g. when iconSize changes from auto functions property int thicknessMidOriginal: Math.max(thicknessNormalOriginal, statesLineSizeOriginal + thickReverseAndGlowExtraSizeOriginal + (1 + (0.65 * (root.zoomFactor-1)))*(root.maxIconSize+root.thickMarginOriginal)) //needed in some animations property int thicknessNormalOriginal: !root.behaveAsPlasmaPanel || root.editMode ? thicknessNormalOriginalValue : root.realPanelSize + root.panelShadow property int thicknessNormalOriginalValue: statesLineSizeOriginal + thickReverseAndGlowExtraSizeOriginal + root.maxIconSize + root.thickMarginOriginal + 1 property int thicknessZoomOriginal: Math.max(statesLineSizeOriginal + thickReverseAndGlowExtraSizeOriginal + ((root.maxIconSize+root.thickMarginOriginal) * root.zoomFactor) + 2, root.realPanelSize + root.panelShadow, thicknessEditMode) property int thicknessEditMode: thicknessNormalOriginalValue + theme.defaultFont.pixelSize + root.editShadow Binding{ target: dock property:"maxThickness" //! prevents updating window geometry during closing window in wayland and such fixes a crash when: dock && !inTempHiding && !inForceHiding value: thicknessZoomOriginal } Binding{ target: dock property:"normalThickness" when: dock value: thicknessNormalOriginal } Binding{ target: dock property: "behaveAsPlasmaPanel" when: dock value: root.editMode ? false : root.behaveAsPlasmaPanel } Binding{ target: dock property: "colorizerSupport" when: dock value: root.forceColorizer && plasmoid.configuration.solidBackgroundForMaximized } Binding{ target: dock property: "dockTransparency" when: dock value: root.currentPanelTransparency } Binding{ target: dock && dock.effects ? dock.effects : null property: "drawShadows" when: dock && dock.effects value: root.drawShadowsExternal && (!root.inStartup || inForceHiding || inTempHiding) } Binding{ target: dock && dock.effects ? dock.effects : null property: "drawEffects" when: dock && dock.effects value: Latte.WindowSystem.compositingActive && (((root.blurEnabled && root.useThemePanel) || (root.blurEnabled && root.forceSolidPanel && dock.visibility.existsWindowMaximized && Latte.WindowSystem.compositingActive)) && (!root.inStartup || inForceHiding || inTempHiding)) } Binding{ target: dock property: "fontPixelSize" when: theme value: theme.defaultFont.pixelSize } Binding{ target: dock property:"inEditMode" when: dock value: root.editMode } Binding{ - target: dock - property:"shadow" - when: dock - value: root.panelShadow + target: dock && dock.effects ? dock.effects : null + property:"innerShadow" + when: dock && dock.effects + value: { + if (editModeVisual.editAnimationEnded && !root.behaveAsPlasmaPanel) { + return root.editShadow; + } else { + return root.panelShadow; + } + } } Binding{ target: dock property: "maxLength" when: dock value: root.editMode ? 1 : plasmoid.configuration.maxLength/100 } Binding{ target: dock property: "offset" when: dock value: plasmoid.configuration.offset } Binding{ target: dock property: "alignment" when: dock value: root.panelAlignment } Binding{ target: dock && dock.visibility ? dock.visibility : null property: "enabledDynamicBackground" when: dock && dock.visibility value: (root.backgroundOnlyOnMaximized || plasmoid.configuration.solidBackgroundForMaximized || root.disablePanelShadowMaximized) && Latte.WindowSystem.compositingActive } Connections{ target:root onPanelShadowChanged: updateMaskArea(); onPanelMarginChanged: updateMaskArea(); } Connections{ target: universalLayoutManager onCurrentLayoutIsSwitching: { if (Latte.WindowSystem.compositingActive && root.dockManagedLayout && root.dockManagedLayout.name === layoutName) { manager.inTempHiding = true; manager.inForceHiding = true; root.clearZoom(); manager.slotMustBeHide(); } } } onNormalStateChanged: { if (normalState) { root.updateAutomaticIconSize(); root.updateSizeForAppletsInFill(); } } onThicknessZoomOriginalChanged: { updateMaskArea(); } function slotContainsMouseChanged() { if(dock.visibility.containsMouse) { updateMaskArea(); } } function slotMustBeShown() { // console.log("show..."); if (!slidingAnimationAutoHiddenIn.running && !inTempHiding && !inForceHiding){ slidingAnimationAutoHiddenIn.init(); } } function slotMustBeHide() { //! prevent sliding-in on startup if the dodge modes have sent a hide signal if (inStartupTimer.running && root.inStartup) { root.inStartup = false; } // console.log("hide...."); if((!slidingAnimationAutoHiddenOut.running && !dock.visibility.blockHiding && !dock.visibility.containsMouse) || inForceHiding) { slidingAnimationAutoHiddenOut.init(); } } //! functions used for sliding out/in during location/screen changes function slotHideDockDuringLocationChange() { inTempHiding = true; blockUpdateMask = true; slotMustBeHide(); } function slotShowDockAfterLocationChange() { slidingAnimationAutoHiddenIn.init(); } function sendHideDockDuringLocationChangeFinished(){ blockUpdateMask = false; dock.positioner.hideDockDuringLocationChangeFinished(); } ///test maskArea function updateMaskArea() { if (!dock || blockUpdateMask) { return; } var localX = 0; var localY = 0; normalState = ((root.animationsNeedBothAxis === 0) && (root.animationsNeedLength === 0)) || (dock.visibility.isHidden && !dock.visibility.containsMouse && root.animationsNeedThickness == 0); // debug maskArea criteria if (debugMagager) { console.log(root.animationsNeedBothAxis + ", " + root.animationsNeedLength + ", " + root.animationsNeedThickness + ", " + dock.visibility.isHidden); if (previousNormalState !== normalState) { console.log("normal state changed to:" + normalState); previousNormalState = normalState; } } var tempLength = root.isHorizontal ? width : height; var tempThickness = root.isHorizontal ? height : width; var space = 0; if (Latte.WindowSystem.compositingActive) { if (root.useThemePanel){ space = root.totalPanelEdgeSpacing + root.panelMarginLength + 1; } else { space = root.totalPanelEdgeSpacing + 1; } } else { space = root.totalPanelEdgeSpacing + root.panelMarginLength; } if (Latte.WindowSystem.compositingActive) { if (normalState) { //console.log("entered normal state..."); //count panel length var noCompositingEdit = !Latte.WindowSystem.compositingActive && root.editMode; //used when !compositing and in editMode if (noCompositingEdit) { tempLength = root.isHorizontal ? root.width : root.height; } else { if(root.isHorizontal) { tempLength = plasmoid.configuration.panelPosition === Latte.Dock.Justify ? layoutsContainer.width + space : layoutsContainer.mainLayout.width + space; } else { tempLength = plasmoid.configuration.panelPosition === Latte.Dock.Justify ? layoutsContainer.height + space : layoutsContainer.mainLayout.height + space; } } tempThickness = thicknessNormal; if (root.animationsNeedThickness > 0) { tempThickness = Latte.WindowSystem.compositingActive ? thicknessZoom : thicknessNormal; } if (dock.visibility.isHidden && !slidingAnimationAutoHiddenOut.running ) { tempThickness = thicknessAutoHidden; } //configure x,y based on plasmoid position and root.panelAlignment(Alignment) if ((plasmoid.location === PlasmaCore.Types.BottomEdge) || (plasmoid.location === PlasmaCore.Types.TopEdge)) { if (plasmoid.location === PlasmaCore.Types.BottomEdge) { localY = dock.visibility.isHidden && dock.visibility.supportsKWinEdges ? dock.height + tempThickness : dock.height - tempThickness; } else if (plasmoid.location === PlasmaCore.Types.TopEdge) { localY = dock.visibility.isHidden && dock.visibility.supportsKWinEdges ? -tempThickness : 0; } if (noCompositingEdit) { localX = 0; } else if (plasmoid.configuration.panelPosition === Latte.Dock.Justify) { localX = (dock.width/2) - tempLength/2 + root.offset; } else if (root.panelAlignment === Latte.Dock.Left) { localX = root.offset; } else if (root.panelAlignment === Latte.Dock.Center) { localX = (dock.width/2) - tempLength/2 + root.offset; } else if (root.panelAlignment === Latte.Dock.Right) { localX = dock.width - layoutsContainer.mainLayout.width - space - root.offset; } } else if ((plasmoid.location === PlasmaCore.Types.LeftEdge) || (plasmoid.location === PlasmaCore.Types.RightEdge)){ if (plasmoid.location === PlasmaCore.Types.LeftEdge) { localX = dock.visibility.isHidden && dock.visibility.supportsKWinEdges ? -tempThickness : 0; } else if (plasmoid.location === PlasmaCore.Types.RightEdge) { localX = dock.visibility.isHidden && dock.visibility.supportsKWinEdges ? dock.width + tempThickness : dock.width - tempThickness; } if (noCompositingEdit) { localY = 0; } else if (plasmoid.configuration.panelPosition === Latte.Dock.Justify) { localY = (dock.height/2) - tempLength/2 + root.offset; } else if (root.panelAlignment === Latte.Dock.Top) { localY = root.offset; } else if (root.panelAlignment === Latte.Dock.Center) { localY = (dock.height/2) - tempLength/2 + root.offset; } else if (root.panelAlignment === Latte.Dock.Bottom) { localY = dock.height - layoutsContainer.mainLayout.height - space - root.offset; } } } else { if(root.isHorizontal) tempLength = Screen.width; //screenGeometry.width; else tempLength = Screen.height; //screenGeometry.height; //grow only on length and not thickness if(root.animationsNeedLength>0 && root.animationsNeedBothAxis === 0) { //this is used to fix a bug with shadow showing when the animation of edit mode //is triggered tempThickness = editModeVisual.editAnimationEnded ? thicknessNormalOriginal + theme.defaultFont.pixelSize + root.editShadow : thicknessNormalOriginal + theme.defaultFont.pixelSize if (dock.visibility.isHidden && !slidingAnimationAutoHiddenOut.running ) { tempThickness = thicknessAutoHidden; } else if (root.animationsNeedThickness > 0) { tempThickness = thicknessZoomOriginal; } } else{ //use all thickness space if (dock.visibility.isHidden && !slidingAnimationAutoHiddenOut.running ) { tempThickness = Latte.WindowSystem.compositingActive ? thicknessAutoHidden : thicknessNormalOriginal; } else { tempThickness = thicknessZoomOriginal; } } //configure the x,y position based on thickness if(plasmoid.location === PlasmaCore.Types.RightEdge) localX = Math.max(0,dock.width - tempThickness); else if(plasmoid.location === PlasmaCore.Types.BottomEdge) localY = Math.max(0,dock.height - tempThickness); } } // end of compositing calculations var maskArea = dock.effects.mask; if (Latte.WindowSystem.compositingActive) { var maskLength = maskArea.width; //in Horizontal if (root.isVertical) { maskLength = maskArea.height; } var maskThickness = maskArea.height; //in Horizontal if (root.isVertical) { maskThickness = maskArea.width; } } else { //! no compositing case if (!dock.visibility.isHidden || !dock.visibility.supportsKWinEdges) { localX = dock.effects.rect.x; localY = dock.effects.rect.y; } else { if (plasmoid.location === PlasmaCore.Types.BottomEdge) { localX = dock.effects.rect.x; localY = dock.effects.rect.y+dock.effects.rect.height+thicknessAutoHidden; } else if (plasmoid.location === PlasmaCore.Types.TopEdge) { localX = dock.effects.rect.x; localY = dock.effects.rect.y - thicknessAutoHidden; } else if (plasmoid.location === PlasmaCore.Types.LeftEdge) { localX = dock.effects.rect.x - thicknessAutoHidden; localY = dock.effects.rect.y; } else if (plasmoid.location === PlasmaCore.Types.RightEdge) { localX = dock.effects.rect.x + dock.effects.rect.width + 1; localY = dock.effects.rect.y; } } if (root.isHorizontal) { tempThickness = dock.effects.rect.height; tempLength = dock.effects.rect.width; } else { tempThickness = dock.effects.rect.width; tempLength = dock.effects.rect.height; } } // console.log("Not updating mask..."); if( maskArea.x !== localX || maskArea.y !== localY || maskLength !== tempLength || maskThickness !== tempThickness) { // console.log("Updating mask..."); var newMaskArea = Qt.rect(-1,-1,0,0); newMaskArea.x = localX; newMaskArea.y = localY; if (isHorizontal) { newMaskArea.width = tempLength; newMaskArea.height = tempThickness; } else { newMaskArea.width = tempThickness; newMaskArea.height = tempLength; } if (!Latte.WindowSystem.compositingActive) { dock.effects.mask = newMaskArea; } else { if (dock.behaveAsPlasmaPanel && !root.editMode) { dock.effects.mask = Qt.rect(0,0,root.width,root.height); } else { dock.effects.mask = newMaskArea; } } } //console.log("reached updating geometry ::: "+dock.maskArea); if(normalState){ var tempGeometry = Qt.rect(dock.effects.mask.x, dock.effects.mask.y, dock.effects.mask.width, dock.effects.mask.height); //the shadows size must be removed from the maskArea //before updating the localDockGeometry if ((!dock.behaveAsPlasmaPanel || root.editMode) && Latte.WindowSystem.compositingActive) { var fixedThickness = root.realPanelThickness; if (plasmoid.formFactor === PlasmaCore.Types.Vertical) { tempGeometry.width = fixedThickness; } else { tempGeometry.height = fixedThickness; } if (plasmoid.location === PlasmaCore.Types.BottomEdge) { tempGeometry.y = dock.height - fixedThickness; } else if (plasmoid.location === PlasmaCore.Types.RightEdge) { tempGeometry.x = dock.width - fixedThickness; } //set the boundaries for dock local geometry //qBound = qMax(min, qMin(value, max)). tempGeometry.x = Math.max(0, Math.min(tempGeometry.x, dock.width)); tempGeometry.y = Math.max(0, Math.min(tempGeometry.y, dock.height)); tempGeometry.width = Math.min(tempGeometry.width, dock.width); tempGeometry.height = Math.min(tempGeometry.height, dock.height); } //console.log("update geometry ::: "+tempGeometry); if (!Latte.WindowSystem.compositingActive) { dock.localGeometry = dock.effects.rect; } else { dock.localGeometry = tempGeometry; } } } Loader{ anchors.fill: parent active: root.debugMode sourceComponent: Item{ anchors.fill:parent Rectangle{ id: windowBackground anchors.fill: parent border.color: "red" border.width: 1 color: "transparent" } Rectangle{ x: dock ? dock.effects.mask.x : -1 y: dock ? dock.effects.mask.y : -1 height: dock ? dock.effects.mask.height : 0 width: dock ? dock.effects.mask.width : 0 border.color: "green" border.width: 1 color: "transparent" } } } /***Hiding/Showing Animations*****/ //////////////// Animations - Slide In - Out SequentialAnimation{ id: slidingAnimationAutoHiddenOut ScriptAction{ script: { root.isHalfShown = true; } } PropertyAnimation { target: layoutsContainer property: root.isVertical ? "x" : "y" to: { if (Latte.WindowSystem.compositingActive) { return slidingOutToPos; } else { if ((plasmoid.location===PlasmaCore.Types.LeftEdge)||(plasmoid.location===PlasmaCore.Types.TopEdge)) { return slidingOutToPos + 1; } else { return slidingOutToPos - 1; } } } duration: manager.animationSpeed easing.type: Easing.InQuad } ScriptAction{ script: { dock.visibility.isHidden = true; } } onStarted: { if (manager.debugMagager) { console.log("hiding animation started..."); } } onStopped: { dock.visibility.isHidden = true; if (manager.debugMagager) { console.log("hiding animation ended..."); } if (!manager.inTempHiding) { updateMaskArea(); } else if (plasmoid.configuration.durationTime === 0) { sendHideDockDuringLocationChangeFinished(); } } function init() { if (!dock.visibility.blockHiding) start(); } } SequentialAnimation{ id: slidingAnimationAutoHiddenIn PauseAnimation{ duration: manager.inTempHiding && root.durationTime>0 ? 500 : 0 } PropertyAnimation { target: layoutsContainer property: root.isVertical ? "x" : "y" to: 0 duration: manager.animationSpeed easing.type: Easing.OutQuad } ScriptAction{ script: { root.isHalfShown = false; root.inStartup = false; } } onStarted: { if (manager.debugMagager) { console.log("showing animation started..."); } } onStopped: { inSlidingIn = false; if (manager.inTempHiding) { manager.inTempHiding = false; updateAutomaticIconSize(); } manager.inTempHiding = false; updateAutomaticIconSize(); if (manager.debugMagager) { console.log("showing animation ended..."); } } function init() { // if (!dock.visibility.blockHiding) inSlidingIn = true; if (slidingAnimationAutoHiddenOut.running) { slidingAnimationAutoHiddenOut.stop(); } dock.visibility.isHidden = false; updateMaskArea(); start(); } } }