diff --git a/app/view/view.cpp b/app/view/view.cpp index c43e87ca..8308bcbb 100644 --- a/app/view/view.cpp +++ b/app/view/view.cpp @@ -1,1098 +1,1099 @@ /* * Copyright 2016 Smith AR * Michail Vourlakos * * This file is part of Latte-Dock * * Latte-Dock is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * Latte-Dock is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "view.h" // local #include "contextmenu.h" #include "effects.h" #include "positioner.h" #include "visibilitymanager.h" #include "settings/primaryconfigview.h" #include "../lattecorona.h" #include "../layoutmanager.h" #include "../layout/layout.h" #include "../plasma/extended/theme.h" #include "../screenpool.h" #include "../settings/universalsettings.h" #include "../shortcuts/globalshortcuts.h" #include "../shortcuts/shortcutstracker.h" #include "../../liblatte2/extras.h" // Qt #include #include #include #include #include #include // KDe #include #include #include #include #include // Plasma #include #include #include namespace Latte { //! both alwaysVisible and byPassWM are passed through corona because //! during the view window creation containment hasn't been set, but these variables //! are needed in order for window flags to be set correctly View::View(Plasma::Corona *corona, QScreen *targetScreen, bool byPassWM) : PlasmaQuick::ContainmentView(corona), m_contextMenu(new ViewPart::ContextMenu(this)), m_effects(new ViewPart::Effects(this)), m_positioner(new ViewPart::Positioner(this)) //needs to be created after Effects because it catches some of its signals { setTitle(corona->kPackage().metadata().name()); setIcon(qGuiApp->windowIcon()); setResizeMode(QuickViewSharedEngine::SizeRootObjectToView); setColor(QColor(Qt::transparent)); setClearBeforeRendering(true); const auto flags = Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::NoDropShadowWindowHint | Qt::WindowDoesNotAcceptFocus; if (byPassWM) { setFlags(flags | Qt::BypassWindowManagerHint); } else { setFlags(flags); } KWindowSystem::setOnAllDesktops(winId(), true); if (targetScreen) m_positioner->setScreenToFollow(targetScreen); else m_positioner->setScreenToFollow(qGuiApp->primaryScreen()); connect(this, &View::containmentChanged , this, [ &, byPassWM]() { qDebug() << "dock view c++ containment changed 1..."; if (!this->containment()) return; qDebug() << "dock view c++ containment changed 2..."; //! First load default values from file restoreConfig(); //! Afterwards override that values in case during creation something different is needed setByPassWM(byPassWM); //! Check the screen assigned to this dock reconsiderScreen(); + //! needs to be created before visibility creation because visibility uses it + if (!m_windowsTracker) { + m_windowsTracker = new ViewPart::WindowsTracker(this); + } + if (!m_visibility) { m_visibility = new ViewPart::VisibilityManager(this); connect(m_visibility, &ViewPart::VisibilityManager::isHiddenChanged, this, [&]() { if (m_visibility->isHidden()) { deactivateApplets(); } }); } - if (!m_windowsTracker) { - m_windowsTracker = new ViewPart::WindowsTracker(this); - } - connect(this->containment(), SIGNAL(statusChanged(Plasma::Types::ItemStatus)), SLOT(statusChanged(Plasma::Types::ItemStatus))); }, Qt::DirectConnection); auto *latteCorona = qobject_cast(this->corona()); if (latteCorona) { connect(latteCorona, &Latte::Corona::viewLocationChanged, this, &View::dockLocationChanged); } } View::~View() { m_inDelete = true; disconnect(corona(), &Plasma::Corona::availableScreenRectChanged, this, &View::availableScreenRectChanged); disconnect(containment(), SIGNAL(statusChanged(Plasma::Types::ItemStatus)), this, SLOT(statusChanged(Plasma::Types::ItemStatus))); qDebug() << "dock view deleting..."; rootContext()->setContextProperty(QStringLiteral("dock"), nullptr); rootContext()->setContextProperty(QStringLiteral("layoutManager"), nullptr); rootContext()->setContextProperty(QStringLiteral("shortcutsEngine"), nullptr); rootContext()->setContextProperty(QStringLiteral("themeExtended"), nullptr); rootContext()->setContextProperty(QStringLiteral("universalSettings"), nullptr); //! this disconnect does not free up connections correctly when //! latteView is deleted. A crash for this example is the following: //! switch to Alternative Session and disable compositing, //! the signal creating the crash was probably from deleted //! windows. //! this->disconnect(); if (m_configView) { m_configView->setVisible(false);//hide(); } if (m_contextMenu) { delete m_contextMenu; } //needs to be deleted before Effects because it catches some of its signals if (m_positioner) { delete m_positioner; } if (m_effects) { delete m_effects; } - if (m_windowsTracker) { - delete m_windowsTracker; - } - if (m_visibility) { delete m_visibility; } + + if (m_windowsTracker) { + delete m_windowsTracker; + } } void View::init() { connect(this, &QQuickWindow::xChanged, this, &View::xChanged); connect(this, &QQuickWindow::xChanged, this, &View::updateAbsDockGeometry); connect(this, &QQuickWindow::yChanged, this, &View::yChanged); connect(this, &QQuickWindow::yChanged, this, &View::updateAbsDockGeometry); connect(this, &QQuickWindow::widthChanged, this, &View::widthChanged); connect(this, &QQuickWindow::widthChanged, this, &View::updateAbsDockGeometry); connect(this, &QQuickWindow::heightChanged, this, &View::heightChanged); connect(this, &QQuickWindow::heightChanged, this, &View::updateAbsDockGeometry); connect(corona(), &Plasma::Corona::availableScreenRectChanged, this, &View::availableScreenRectChanged); connect(this, &View::byPassWMChanged, this, &View::saveConfig); connect(this, &View::onPrimaryChanged, this, &View::saveConfig); connect(this, &View::isPreferredForShortcutsChanged, this, &View::saveConfig); connect(this, SIGNAL(normalThicknessChanged()), corona(), SIGNAL(availableScreenRectChanged())); connect(m_positioner, &ViewPart::Positioner::onHideWindowsForSlidingOut, this, &View::hideWindowsForSlidingOut); connect(m_positioner, &ViewPart::Positioner::screenGeometryChanged, this, &View::screenGeometryChanged); connect(m_contextMenu, &ViewPart::ContextMenu::menuChanged, this, &View::contextMenuIsShownChanged); ///!!!!! rootContext()->setContextProperty(QStringLiteral("latteView"), this); auto *latteCorona = qobject_cast(this->corona()); if (latteCorona) { rootContext()->setContextProperty(QStringLiteral("layoutManager"), latteCorona->layoutManager()); rootContext()->setContextProperty(QStringLiteral("shortcutsEngine"), latteCorona->globalShortcuts()->shortcutsTracker()); rootContext()->setContextProperty(QStringLiteral("themeExtended"), latteCorona->themeExtended()); rootContext()->setContextProperty(QStringLiteral("universalSettings"), latteCorona->universalSettings()); } setSource(corona()->kPackage().filePath("lattedockui")); // setVisible(true); m_positioner->syncGeometry(); if (!KWindowSystem::isPlatformWayland()) { setVisible(true); } qDebug() << "SOURCE:" << source(); } bool View::inDelete() const { return m_inDelete; } void View::disconnectSensitiveSignals() { disconnect(corona(), &Plasma::Corona::availableScreenRectChanged, this, &View::availableScreenRectChanged); setManagedLayout(nullptr); if (m_windowsTracker) { m_windowsTracker->setEnabled(false); } } void View::availableScreenRectChanged() { if (m_inDelete) return; if (formFactor() == Plasma::Types::Vertical) { m_positioner->syncGeometry(); } } void View::setupWaylandIntegration() { if (m_shellSurface) return; if (Latte::Corona *c = qobject_cast(corona())) { using namespace KWayland::Client; PlasmaShell *interface {c->waylandCoronaInterface()}; if (!interface) return; Surface *s{Surface::fromWindow(this)}; if (!s) return; m_shellSurface = interface->createSurface(s, this); qDebug() << "WAYLAND dock window surface was created..."; m_shellSurface->setSkipTaskbar(true); m_shellSurface->setRole(PlasmaShellSurface::Role::Panel); m_shellSurface->setPanelBehavior(PlasmaShellSurface::PanelBehavior::WindowsGoBelow); } } KWayland::Client::PlasmaShellSurface *View::surface() { return m_shellSurface; } //! the main function which decides if this dock is at the //! correct screen void View::reconsiderScreen() { m_positioner->reconsiderScreen(); } void View::copyView() { m_managedLayout->copyView(containment()); } void View::removeView() { if (m_managedLayout && m_managedLayout->viewsCount() > 1) { QAction *removeAct = this->containment()->actions()->action(QStringLiteral("remove")); if (removeAct) { removeAct->trigger(); } } } bool View::settingsWindowIsShown() { auto configView = qobject_cast(m_configView); return (configView != nullptr); } void View::showSettingsWindow() { if (!settingsWindowIsShown()) { emit m_visibility->mustBeShown(); showConfigurationInterface(containment()); applyActivitiesToWindows(); } } void View::showConfigurationInterface(Plasma::Applet *applet) { if (!applet || !applet->containment()) return; Plasma::Containment *c = qobject_cast(applet); if (m_configView && c && c->isContainment() && c == this->containment()) { if (m_configView->isVisible()) { m_configView->setVisible(false); //m_configView->hide(); } else { m_configView->setVisible(true); //m_configView->show(); } return; } else if (m_configView) { if (m_configView->applet() == applet) { m_configView->setVisible(true); //m_configView->show(); m_configView->requestActivate(); return; } else { m_configView->setVisible(false); //m_configView->hide(); m_configView->deleteLater(); } } bool delayConfigView = false; if (c && containment() && c->isContainment() && c->id() == this->containment()->id()) { m_configView = new ViewPart::PrimaryConfigView(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 containment's layouts the time to //calculate the window's height if (!KWindowSystem::isPlatformWayland()) { QTimer::singleShot(150, m_configView, SLOT(show())); } else { QTimer::singleShot(150, [this]() { m_configView->setVisible(true); }); } } } QRect View::localGeometry() const { return m_localGeometry; } void View::setLocalGeometry(const QRect &geometry) { if (m_localGeometry == geometry) { return; } m_localGeometry = geometry; emit localGeometryChanged(); updateAbsDockGeometry(); } void View::updateAbsDockGeometry(bool bypassChecks) { //! there was a -1 in height and width here. The reason of this //! if I remember correctly was related to multi-screen but I cant //! remember exactly the reason, something related to right 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() == Types::AlwaysVisible) { emit corona()->availableScreenRectChanged(); emit corona()->availableScreenRegionChanged(); } } void View::statusChanged(Plasma::Types::ItemStatus status) { if (containment()) { if (containment()->status() >= Plasma::Types::NeedsAttentionStatus && containment()->status() != Plasma::Types::HiddenStatus) { setBlockHiding(true); } else if (!containment()->isUserConfiguring()){ setBlockHiding(false); } } } bool View::alternativesIsShown() const { return m_alternativesIsShown; } void View::setAlternativesIsShown(bool show) { if (m_alternativesIsShown == show) { return; } m_alternativesIsShown = show; setBlockHiding(show); emit alternativesIsShownChanged(); } bool View::contextMenuIsShown() const { if (!m_contextMenu) { return false; } return m_contextMenu->menu(); } int View::currentThickness() const { if (formFactor() == Plasma::Types::Vertical) { return m_effects->mask().isNull() ? width() : m_effects->mask().width() - m_effects->innerShadow(); } else { return m_effects->mask().isNull() ? height() : m_effects->mask().height() - m_effects->innerShadow(); } } int View::normalThickness() const { return m_normalThickness; } void View::setNormalThickness(int thickness) { if (m_normalThickness == thickness) { return; } m_normalThickness = thickness; emit normalThicknessChanged(); } bool View::byPassWM() const { return m_byPassWM; } void View::setByPassWM(bool bypass) { if (m_byPassWM == bypass) { return; } m_byPassWM = bypass; emit byPassWMChanged(); } bool View::behaveAsPlasmaPanel() const { return m_behaveAsPlasmaPanel; } void View::setBehaveAsPlasmaPanel(bool behavior) { if (m_behaveAsPlasmaPanel == behavior) { return; } m_behaveAsPlasmaPanel = behavior; emit behaveAsPlasmaPanelChanged(); } bool View::inEditMode() const { return m_inEditMode; } void View::setInEditMode(bool edit) { if (m_inEditMode == edit) { return; } m_inEditMode = edit; emit inEditModeChanged(); } bool View::isPreferredForShortcuts() const { return m_isPreferredForShortcuts; } void View::setIsPreferredForShortcuts(bool preferred) { if (m_isPreferredForShortcuts == preferred) { return; } m_isPreferredForShortcuts = preferred; emit isPreferredForShortcutsChanged(); if (m_isPreferredForShortcuts && m_managedLayout) { emit m_managedLayout->preferredViewForShortcutsChanged(this); } } void View::preferredViewForShortcutsChangedSlot(Latte::View *view) { if (view != this) { setIsPreferredForShortcuts(false); } } bool View::onPrimary() const { return m_onPrimary; } void View::setOnPrimary(bool flag) { if (m_onPrimary == flag) { return; } m_onPrimary = flag; emit onPrimaryChanged(); } float View::maxLength() const { return m_maxLength; } void View::setMaxLength(float length) { if (m_maxLength == length) { return; } m_maxLength = length; emit maxLengthChanged(); } int View::maxThickness() const { return m_maxThickness; } void View::setMaxThickness(int thickness) { if (m_maxThickness == thickness) return; m_maxThickness = thickness; emit maxThicknessChanged(); } int View::alignment() const { return m_alignment; } void View::setAlignment(int alignment) { Types::Alignment align = static_cast(alignment); if (m_alignment == alignment) { return; } m_alignment = align; emit alignmentChanged(); } QRect View::absGeometry() const { return m_absGeometry; } QRect View::screenGeometry() const { if (this->screen()) { QRect geom = this->screen()->geometry(); return geom; } return QRect(); } int View::offset() const { return m_offset; } void View::setOffset(int offset) { if (m_offset == offset) { return; } m_offset = offset; emit offsetChanged(); } int View::fontPixelSize() const { return m_fontPixelSize; } void View::setFontPixelSize(int size) { if (m_fontPixelSize == size) { return; } m_fontPixelSize = size; emit fontPixelSizeChanged(); } void View::applyActivitiesToWindows() { if (m_visibility) { QStringList activities = m_managedLayout->appliedActivities(); m_windowsTracker->setWindowOnActivities(*this, activities); if (m_configView) { m_windowsTracker->setWindowOnActivities(*m_configView, activities); auto configView = qobject_cast(m_configView); if (configView && configView->secondaryWindow()) { m_windowsTracker->setWindowOnActivities(*configView->secondaryWindow(), activities); } } if (m_visibility->supportsKWinEdges()) { m_visibility->applyActivitiesToHiddenWindows(activities); } } } Layout *View::managedLayout() const { return m_managedLayout; } void View::setManagedLayout(Layout *layout) { if (m_managedLayout == layout) { return; } // clear mode for (auto &c : connectionsManagedLayout) { disconnect(c); } m_managedLayout = layout; if (m_managedLayout) { //! Sometimes the activity isnt completely ready, by adding a delay //! we try to catch up QTimer::singleShot(100, [this]() { if (m_managedLayout && m_visibility) { qDebug() << "DOCK VIEW FROM LAYOUT ::: " << m_managedLayout->name() << " - activities: " << m_managedLayout->appliedActivities(); applyActivitiesToWindows(); emit activitiesChanged(); } }); connectionsManagedLayout[0] = connect(m_managedLayout, &Layout::preferredViewForShortcutsChanged, this, &View::preferredViewForShortcutsChangedSlot); } Latte::Corona *latteCorona = qobject_cast(this->corona()); if (latteCorona->layoutManager()->memoryUsage() == Types::MultipleLayouts) { connectionsManagedLayout[1] = connect(latteCorona->activitiesConsumer(), &KActivities::Consumer::runningActivitiesChanged, this, [&]() { if (m_managedLayout && m_visibility) { qDebug() << "DOCK VIEW FROM LAYOUT (runningActivitiesChanged) ::: " << m_managedLayout->name() << " - activities: " << m_managedLayout->appliedActivities(); applyActivitiesToWindows(); emit activitiesChanged(); } }); connectionsManagedLayout[2] = connect(m_managedLayout, &Layout::activitiesChanged, this, [&]() { if (m_managedLayout) { applyActivitiesToWindows(); emit activitiesChanged(); } }); connectionsManagedLayout[3] = connect(latteCorona->layoutManager(), &LayoutManager::layoutsChanged, this, [&]() { if (m_managedLayout) { applyActivitiesToWindows(); emit activitiesChanged(); } }); //!IMPORTANT!!! ::: This fixes a bug when closing an Activity all docks from all Activities are //! disappearing! With this they reappear!!! connectionsManagedLayout[4] = connect(this, &QWindow::visibleChanged, this, [&]() { if (!isVisible() && m_managedLayout) { QTimer::singleShot(100, [this]() { if (m_managedLayout && containment() && !containment()->destroyed()) { setVisible(true); applyActivitiesToWindows(); emit activitiesChanged(); } }); QTimer::singleShot(1500, [this]() { if (m_managedLayout && containment() && !containment()->destroyed()) { setVisible(true); applyActivitiesToWindows(); emit activitiesChanged(); } }); } }); } emit managedLayoutChanged(); } void View::moveToLayout(QString layoutName) { if (!m_managedLayout) { return; } QList containments = m_managedLayout->unassignFromLayout(this); Latte::Corona *latteCorona = qobject_cast(this->corona()); if (latteCorona && containments.size() > 0) { Layout *newLayout = latteCorona->layoutManager()->activeLayout(layoutName); if (newLayout) { newLayout->assignToLayout(this, containments); } } } void View::setBlockHiding(bool block) { if (!block) { auto *configView = qobject_cast(m_configView); if (m_alternativesIsShown || (configView && configView->sticker() && configView->isVisible())) { return; } if (m_visibility) { m_visibility->setBlockHiding(false); } } else { if (m_visibility) { m_visibility->setBlockHiding(true); } } } void View::hideWindowsForSlidingOut() { setBlockHiding(false); if (m_configView) { auto configDialog = qobject_cast(m_configView); if (configDialog) { configDialog->hideConfigWindow(); } } } //! remove latte tasks plasmoid void View::removeTasksPlasmoid() { if (!tasksPresent() || !containment()) { return; } foreach (Plasma::Applet *applet, containment()->applets()) { KPluginMetaData meta = applet->kPackage().metadata(); if (meta.pluginId() == "org.kde.latte.plasmoid") { QAction *closeApplet = applet->actions()->action(QStringLiteral("remove")); if (closeApplet) { closeApplet->trigger(); //! remove only the first found return; } } } } //! check if the tasks plasmoid exist in the dock bool View::tasksPresent() { if (!this->containment()) { return false; } foreach (Plasma::Applet *applet, this->containment()->applets()) { const auto &provides = KPluginMetaData::readStringList(applet->pluginMetaData().rawData(), QStringLiteral("X-Plasma-Provides")); if (provides.contains(QLatin1String("org.kde.plasma.multitasking"))) { return true; } } return false; } //! check if the tasks plasmoid exist in the dock bool View::latteTasksPresent() { if (!this->containment()) { return false; } foreach (Plasma::Applet *applet, this->containment()->applets()) { KPluginMetaData metadata = applet->pluginMetaData(); if (metadata.pluginId() == "org.kde.latte.plasmoid") { return true; } } return false; } //!check if the plasmoid with _name_ exists in the midedata bool View::mimeContainsPlasmoid(QMimeData *mimeData, QString name) { if (!mimeData) { return false; } if (mimeData->hasFormat(QStringLiteral("text/x-plasmoidservicename"))) { QString data = mimeData->data(QStringLiteral("text/x-plasmoidservicename")); const QStringList appletNames = data.split('\n', QString::SkipEmptyParts); foreach (const QString &appletName, appletNames) { if (appletName == name) return true; } } return false; } ViewPart::Effects *View::effects() const { return m_effects; } ViewPart::Positioner *View::positioner() const { return m_positioner; } ViewPart::VisibilityManager *View::visibility() const { return m_visibility; } ViewPart::WindowsTracker *View::windowsTracker() const { return m_windowsTracker; } bool View::event(QEvent *e) { if (!m_inDelete) { emit eventTriggered(e); switch (e->type()) { case QEvent::Leave: engine()->trimComponentCache(); break; case QEvent::PlatformSurface: if (auto pe = dynamic_cast(e)) { switch (pe->surfaceEventType()) { case QPlatformSurfaceEvent::SurfaceCreated: setupWaylandIntegration(); if (m_shellSurface) { m_positioner->syncGeometry(); m_effects->updateShadows(); } break; case QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed: if (m_shellSurface) { delete m_shellSurface; m_shellSurface = nullptr; qDebug() << "WAYLAND dock window surface was deleted..."; m_effects->clearShadows(); } break; } } break; default: break; } } return ContainmentView::event(e);; } void View::deactivateApplets() { if (!containment()) { return; } foreach (auto applet, containment()->applets()) { PlasmaQuick::AppletQuickItem *ai = applet->property("_plasma_graphicObject").value(); if (ai) { ai->setExpanded(false); } } } void View::toggleAppletExpanded(const int id) { if (!containment()) { return; } foreach (auto applet, containment()->applets()) { if (applet->id() == id) { PlasmaQuick::AppletQuickItem *ai = applet->property("_plasma_graphicObject").value(); if (ai) { if (!ai->isActivationTogglesExpanded()) { ai->setActivationTogglesExpanded(true); } emit applet->activated(); } } } } QVariantList View::containmentActions() { QVariantList actions; /*if (containment()->corona()->immutability() != Plasma::Types::Mutable) { return actions; }*/ //FIXME: the trigger string it should be better to be supported this way //const QString trigger = Plasma::ContainmentActions::eventToString(event); const QString trigger = "RightButton;NoModifier"; Plasma::ContainmentActions *plugin = this->containment()->containmentActions().value(trigger); if (!plugin) { return actions; } if (plugin->containment() != this->containment()) { plugin->setContainment(this->containment()); // now configure it KConfigGroup cfg(this->containment()->corona()->config(), "ActionPlugins"); cfg = KConfigGroup(&cfg, QString::number(this->containment()->containmentType())); KConfigGroup pluginConfig = KConfigGroup(&cfg, trigger); plugin->restore(pluginConfig); } foreach (QAction *ac, plugin->contextualActions()) { actions << QVariant::fromValue(ac); } return actions; } void View::disableGrabItemBehavior() { setMouseGrabEnabled(false); } void View::restoreGrabItemBehavior() { if (mouseGrabberItem()) { mouseGrabberItem()->ungrabMouse(); } } bool View::isHighestPriorityView() { if (m_managedLayout) { return this == m_managedLayout->highestPriorityView(); } return false; } //!BEGIN overriding context menus behavior void View::mousePressEvent(QMouseEvent *event) { bool result = m_contextMenu->mousePressEvent(event); emit contextMenuIsShownChanged(); if (result) { PlasmaQuick::ContainmentView::mousePressEvent(event); } } //!END overriding context menus behavior //!BEGIN configuration functions void View::saveConfig() { if (!this->containment()) return; auto config = this->containment()->config(); config.writeEntry("onPrimary", onPrimary()); config.writeEntry("byPassWM", byPassWM()); config.writeEntry("isPreferredForShortcuts", isPreferredForShortcuts()); config.sync(); } void View::restoreConfig() { if (!this->containment()) return; auto config = this->containment()->config(); m_onPrimary = config.readEntry("onPrimary", true); m_byPassWM = config.readEntry("byPassWM", false); m_isPreferredForShortcuts = config.readEntry("isPreferredForShortcuts", false); //! Send changed signals at the end in order to be sure that saveConfig //! wont rewrite default/invalid values emit onPrimaryChanged(); emit byPassWMChanged(); } //!END configuration functions } //!END namespace diff --git a/app/view/visibilitymanager.cpp b/app/view/visibilitymanager.cpp index 173bd72f..7c3f5ee6 100644 --- a/app/view/visibilitymanager.cpp +++ b/app/view/visibilitymanager.cpp @@ -1,840 +1,768 @@ /* * Copyright 2016 Smith AR * Michail Vourlakos * * This file is part of Latte-Dock * * Latte-Dock is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * Latte-Dock is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "visibilitymanager.h" // local #include "positioner.h" #include "screenedgeghostwindow.h" #include "view.h" #include "../lattecorona.h" #include "../layoutmanager.h" #include "../screenpool.h" #include "../wm/windowinfowrap.h" #include "../../liblatte2/extras.h" // Qt #include // KDE #include #include namespace Latte { namespace ViewPart { //! BEGIN: VisiblityManager implementation VisibilityManager::VisibilityManager(PlasmaQuick::ContainmentView *view) : QObject(view) { qDebug() << "VisibilityManager creating..."; m_latteView = qobject_cast(view); m_corona = qobject_cast(view->corona()); wm = m_corona->wm(); if (m_latteView) { connect(m_latteView, &Latte::View::absGeometryChanged, this, &VisibilityManager::setViewGeometry); connect(m_latteView, &Latte::View::eventTriggered, this, &VisibilityManager::viewEventManager); } if (m_corona) { connect(this, &VisibilityManager::modeChanged, m_corona, &Plasma::Corona::availableScreenRectChanged); } m_timerStartUp.setInterval(5000); m_timerStartUp.setSingleShot(true); - m_timerCheckWindows.setInterval(350); - m_timerCheckWindows.setSingleShot(true); m_timerShow.setSingleShot(true); m_timerHide.setSingleShot(true); - connect(&m_timerCheckWindows, &QTimer::timeout, this, &VisibilityManager::checkAllWindows); + connect(&m_timerShow, &QTimer::timeout, this, [&]() { if (m_isHidden) { // qDebug() << "must be shown"; emit mustBeShown(); } }); connect(&m_timerHide, &QTimer::timeout, this, [&]() { if (!m_blockHiding && !m_isHidden && !dragEnter) { // qDebug() << "must be hide"; emit mustBeHide(); } }); wm->setViewExtraFlags(*m_latteView); wm->addView(m_latteView->winId()); restoreConfig(); } VisibilityManager::~VisibilityManager() { qDebug() << "VisibilityManager deleting..."; wm->removeViewStruts(*m_latteView); wm->removeView(m_latteView->winId()); if (edgeGhostWindow) { edgeGhostWindow->deleteLater(); } } Types::Visibility VisibilityManager::mode() const { return m_mode; } void VisibilityManager::setMode(Latte::Types::Visibility mode) { if (m_mode == mode) return; Q_ASSERT_X(m_mode != Types::None, staticMetaObject.className(), "set visibility to Types::None"); // clear mode for (auto &c : connections) { disconnect(c); } - if (m_mode != Types::DodgeAllWindows) { - windows.clear(); - } - if (m_mode == Types::AlwaysVisible) { wm->removeViewStruts(*m_latteView); } else { connections[3] = connect(wm, &WindowSystem::currentDesktopChanged , this, [&] { if (raiseOnDesktopChange) raiseViewTemporarily(); }); connections[4] = connect(wm, &WindowSystem::currentActivityChanged , this, [&]() { if (raiseOnActivityChange) raiseViewTemporarily(); else updateHiddenState(); }); } m_timerShow.stop(); m_timerHide.stop(); - m_timerCheckWindows.stop(); m_mode = mode; switch (m_mode) { case Types::AlwaysVisible: { //set wayland visibility mode if (m_latteView->surface()) { m_latteView->surface()->setPanelBehavior(KWayland::Client::PlasmaShellSurface::PanelBehavior::WindowsGoBelow); } if (m_latteView->containment() && !m_latteView->inEditMode() && m_latteView->screen()) { updateStrutsBasedOnLayoutsAndActivities(); } connections[0] = connect(m_latteView->containment(), &Plasma::Containment::locationChanged , this, [&]() { if (m_latteView->inEditMode()) wm->removeViewStruts(*m_latteView); }); connections[1] = connect(m_latteView, &Latte::View::inEditModeChanged , this, [&]() { if (!m_latteView->inEditMode() && !m_latteView->positioner()->inLocationChangeAnimation() && m_latteView->screen()) wm->setViewStruts(*m_latteView, m_viewGeometry, m_latteView->containment()->location()); }); if (m_corona && m_corona->layoutManager()->memoryUsage() == Types::MultipleLayouts) { connections[2] = connect(m_corona->activitiesConsumer(), &KActivities::Consumer::currentActivityChanged, this, [&]() { updateStrutsBasedOnLayoutsAndActivities(); }); connections[3] = connect(m_latteView, &Latte::View::activitiesChanged, this, [&]() { updateStrutsBasedOnLayoutsAndActivities(); }); } raiseView(true); } break; case Types::AutoHide: { //set wayland visibility mode if (m_latteView->surface()) { m_latteView->surface()->setPanelBehavior(KWayland::Client::PlasmaShellSurface::PanelBehavior::AutoHide); } raiseView(m_containsMouse); } break; case Types::DodgeActive: { //set wayland visibility mode if (m_latteView->surface()) { m_latteView->surface()->setPanelBehavior(KWayland::Client::PlasmaShellSurface::PanelBehavior::AutoHide); } connections[0] = connect(wm, &WindowSystem::activeWindowChanged , this, &VisibilityManager::dodgeActive); connections[1] = connect(wm, &WindowSystem::windowChanged , this, &VisibilityManager::dodgeActive); dodgeActive(wm->activeWindow()); } break; case Types::DodgeMaximized: { //set wayland visibility mode if (m_latteView->surface()) { m_latteView->surface()->setPanelBehavior(KWayland::Client::PlasmaShellSurface::PanelBehavior::AutoHide); } connections[0] = connect(wm, &WindowSystem::activeWindowChanged , this, &VisibilityManager::dodgeMaximized); connections[1] = connect(wm, &WindowSystem::windowChanged , this, &VisibilityManager::dodgeMaximized); dodgeMaximized(wm->activeWindow()); } break; case Types::DodgeAllWindows: { //set wayland visibility mode if (m_latteView->surface()) { m_latteView->surface()->setPanelBehavior(KWayland::Client::PlasmaShellSurface::PanelBehavior::AutoHide); } - for (const auto &wid : wm->windows()) { - windows.insert(wid, wm->requestInfo(wid)); - } + connections[0] = connect(this, &VisibilityManager::containsMouseChanged + , this, &VisibilityManager::dodgeAllWindows); - connections[0] = connect(wm, &WindowSystem::windowChanged - , this, &VisibilityManager::dodgeWindows); - connections[1] = connect(wm, &WindowSystem::windowRemoved - , this, [&](WindowId wid) { - windows.remove(wid); - m_timerCheckWindows.start(); - }); - connections[2] = connect(wm, &WindowSystem::windowAdded - , this, [&](WindowId wid) { - windows.insert(wid, wm->requestInfo(wid)); - m_timerCheckWindows.start(); - }); + connections[1] = connect(m_latteView->windowsTracker(), &WindowsTracker::existsWindowTouchingChanged + , this, &VisibilityManager::dodgeAllWindows); - m_timerCheckWindows.start(); + connections[2] = connect(m_latteView->windowsTracker(), &WindowsTracker::activeWindowTouchingChanged + , this, &VisibilityManager::dodgeAllWindows); } break; case Types::WindowsGoBelow: //set wayland visibility mode if (m_latteView->surface()) { m_latteView->surface()->setPanelBehavior(KWayland::Client::PlasmaShellSurface::PanelBehavior::WindowsGoBelow); } break; default: break; } m_latteView->containment()->config().writeEntry("visibility", static_cast(m_mode)); updateKWinEdgesSupport(); emit modeChanged(); } void VisibilityManager::updateStrutsBasedOnLayoutsAndActivities() { bool multipleLayoutsAndCurrent = (m_corona->layoutManager()->memoryUsage() == Types::MultipleLayouts && m_latteView->managedLayout() && !m_latteView->positioner()->inLocationChangeAnimation() && m_latteView->managedLayout()->name() == m_corona->layoutManager()->currentLayoutName()); if (m_corona->layoutManager()->memoryUsage() == Types::SingleLayout || multipleLayoutsAndCurrent) { wm->setViewStruts(*m_latteView, m_viewGeometry, m_latteView->location()); } else { wm->removeViewStruts(*m_latteView); } } bool VisibilityManager::raiseOnDesktop() const { return raiseOnDesktopChange; } void VisibilityManager::setRaiseOnDesktop(bool enable) { if (enable == raiseOnDesktopChange) return; raiseOnDesktopChange = enable; emit raiseOnDesktopChanged(); } bool VisibilityManager::raiseOnActivity() const { return raiseOnActivityChange; } void VisibilityManager::setRaiseOnActivity(bool enable) { if (enable == raiseOnActivityChange) return; raiseOnActivityChange = enable; emit raiseOnActivityChanged(); } bool VisibilityManager::isHidden() const { return m_isHidden; } void VisibilityManager::setIsHidden(bool isHidden) { if (m_isHidden == isHidden) return; if (m_blockHiding && isHidden) { qWarning() << "isHidden property is blocked, ignoring update"; return; } m_isHidden = isHidden; if (supportsKWinEdges()) { bool inCurrentLayout = (m_corona->layoutManager()->memoryUsage() == Types::SingleLayout || (m_corona->layoutManager()->memoryUsage() == Types::MultipleLayouts && m_latteView->managedLayout() && !m_latteView->positioner()->inLocationChangeAnimation() && m_latteView->managedLayout()->name() == m_corona->layoutManager()->currentLayoutName())); if (inCurrentLayout) { wm->setEdgeStateFor(edgeGhostWindow, m_isHidden); } else { wm->setEdgeStateFor(edgeGhostWindow, false); } } emit isHiddenChanged(); } bool VisibilityManager::blockHiding() const { return m_blockHiding; } void VisibilityManager::setBlockHiding(bool blockHiding) { if (m_blockHiding == blockHiding) { return; } m_blockHiding = blockHiding; // qDebug() << "blockHiding:" << blockHiding; if (m_blockHiding) { m_timerHide.stop(); if (m_isHidden) { emit mustBeShown(); } } else { updateHiddenState(); } emit blockHidingChanged(); } int VisibilityManager::timerShow() const { return m_timerShow.interval(); } void VisibilityManager::setTimerShow(int msec) { m_timerShow.setInterval(msec); emit timerShowChanged(); } int VisibilityManager::timerHide() const { return m_timerHide.interval(); } void VisibilityManager::setTimerHide(int msec) { m_timerHide.setInterval(msec); emit timerHideChanged(); } bool VisibilityManager::supportsKWinEdges() const { return (edgeGhostWindow != nullptr); } void VisibilityManager::raiseView(bool raise) { if (m_blockHiding) return; if (raise) { m_timerHide.stop(); if (!m_timerShow.isActive()) { m_timerShow.start(); } } else if (!dragEnter) { m_timerShow.stop(); if (hideNow) { hideNow = false; emit mustBeHide(); } else if (!m_timerHide.isActive()) { m_timerHide.start(); } } } void VisibilityManager::raiseViewTemporarily() { if (raiseTemporarily) return; raiseTemporarily = true; m_timerHide.stop(); m_timerShow.stop(); if (m_isHidden) emit mustBeShown(); QTimer::singleShot(qBound(1800, 2 * m_timerHide.interval(), 3000), this, [&]() { raiseTemporarily = false; hideNow = true; updateHiddenState(); }); } void VisibilityManager::updateHiddenState() { if (dragEnter) return; switch (m_mode) { case Types::AutoHide: raiseView(m_containsMouse); break; case Types::DodgeActive: dodgeActive(wm->activeWindow()); break; case Types::DodgeMaximized: dodgeMaximized(wm->activeWindow()); break; case Types::DodgeAllWindows: - dodgeWindows(wm->activeWindow()); + dodgeAllWindows(); break; default: break; } } void VisibilityManager::setViewGeometry(const QRect &geometry) { if (!m_latteView->containment()) return; m_viewGeometry = geometry; if (m_mode == Types::AlwaysVisible && !m_latteView->inEditMode() && m_latteView->screen()) { updateStrutsBasedOnLayoutsAndActivities(); } } void VisibilityManager::applyActivitiesToHiddenWindows(const QStringList &activities) { if (edgeGhostWindow) { wm->setWindowOnActivities(*edgeGhostWindow, activities); } } void VisibilityManager::activeWindowDraggingStarted() { setContainsMouse(false); updateHiddenState(); } void VisibilityManager::dodgeActive(WindowId wid) { if (raiseTemporarily) return; //!don't send false raiseView signal when containing mouse if (m_containsMouse) { raiseView(true); return; } auto winfo = wm->requestInfo(wid); if (!winfo.isValid() || !winfo.isActive()) { winfo = wm->requestInfo(wm->activeWindow()); if (!winfo.isValid()) { //! very rare case that window manager doesn't have any active window at all raiseView(true); return; } } //! don't send false raiseView signal when containing mouse, // Johan comment //! I don't know why that wasn't winfo.wid() //active window, but just wid//the window that made the call if (wm->isOnCurrentDesktop(winfo.wid()) && wm->isOnCurrentActivity(winfo.wid())) { bool overlaps{intersects(winfo)}; raiseView(!overlaps); } } void VisibilityManager::dodgeMaximized(WindowId wid) { if (raiseTemporarily) return; //!don't send false raiseView signal when containing mouse if (m_containsMouse) { raiseView(true); return; } auto winfo = wm->requestInfo(wid); if (!winfo.isValid() || !winfo.isActive()) { winfo = wm->requestInfo(wm->activeWindow()); if (!winfo.isValid()) { //! very rare case that window manager doesn't have any active window at all raiseView(true); return; } } auto intersectsMaxVert = [&]() noexcept -> bool { return ((winfo.isMaxVert() || (m_latteView->screen() && m_latteView->screen()->availableSize().height() <= winfo.geometry().height())) && intersects(winfo)); }; auto intersectsMaxHoriz = [&]() noexcept -> bool { return ((winfo.isMaxHoriz() || (m_latteView->screen() && m_latteView->screen()->availableSize().width() <= winfo.geometry().width())) && intersects(winfo)); }; //! don't send false raiseView signal when containing mouse, // Johan comment //! I don't know why that wasn't winfo.wid() //active window, but just wid//the window that made the call if (wm->isOnCurrentDesktop(winfo.wid()) && wm->isOnCurrentActivity(winfo.wid())) { bool overlapsMaximized{m_latteView->formFactor() == Plasma::Types::Vertical ? intersectsMaxHoriz() : intersectsMaxVert()}; raiseView(!overlapsMaximized); } } -void VisibilityManager::dodgeWindows(WindowId wid) +void VisibilityManager::dodgeAllWindows() { if (raiseTemporarily) return; - if (windows.find(wid) == std::end(windows)) - return; - - //!don't send false raiseView signal when containing mouse if (m_containsMouse) { raiseView(true); - return; } - windows[wid] = wm->requestInfo(wid); - auto &winfo = windows[wid]; - - if (!winfo.isValid() || !wm->isOnCurrentDesktop(wid) || !wm->isOnCurrentActivity(wid)) - return; + bool windowIntersects{m_latteView->windowsTracker()->activeWindowTouching() || m_latteView->windowsTracker()->existsWindowTouching()}; - if (intersects(winfo)) - raiseView(false); - else - m_timerCheckWindows.start(); -} - -void VisibilityManager::checkAllWindows() -{ - if (raiseTemporarily) - return; - - bool raise{true}; - bool existsFaultyWindow{false}; - - for (const auto &winfo : windows) { - // - if (winfo.geometry() == QRect(0, 0, 0, 0)) { - existsFaultyWindow = true; - } - - if (!winfo.isValid() || !wm->isOnCurrentDesktop(winfo.wid()) || !wm->isOnCurrentActivity(winfo.wid())) - continue; - - if (winfo.isFullscreen()) { - raise = false; - break; - } else if (intersects(winfo)) { - raise = false; - break; - } - } - - cleanupFaultyWindows(); - raiseView(raise); + raiseView(!windowIntersects); } bool VisibilityManager::intersects(const WindowInfoWrap &winfo) { return (!winfo.isMinimized() && wm->isOnCurrentDesktop(winfo.wid()) && wm->isOnCurrentActivity(winfo.wid()) && winfo.geometry().intersects(m_viewGeometry) && !winfo.isShaded()); } void VisibilityManager::saveConfig() { if (!m_latteView->containment()) return; auto config = m_latteView->containment()->config(); config.writeEntry("enableKWinEdges", enableKWinEdgesFromUser); config.writeEntry("timerShow", m_timerShow.interval()); config.writeEntry("timerHide", m_timerHide.interval()); config.writeEntry("raiseOnDesktopChange", raiseOnDesktopChange); config.writeEntry("raiseOnActivityChange", raiseOnActivityChange); m_latteView->containment()->configNeedsSaving(); } void VisibilityManager::restoreConfig() { if (!m_latteView || !m_latteView->containment()){ return; } auto config = m_latteView->containment()->config(); m_timerShow.setInterval(config.readEntry("timerShow", 0)); m_timerHide.setInterval(config.readEntry("timerHide", 700)); emit timerShowChanged(); emit timerHideChanged(); enableKWinEdgesFromUser = config.readEntry("enableKWinEdges", true); emit enableKWinEdgesChanged(); setRaiseOnDesktop(config.readEntry("raiseOnDesktopChange", false)); setRaiseOnActivity(config.readEntry("raiseOnActivityChange", false)); auto storedMode = static_cast(m_latteView->containment()->config().readEntry("visibility", static_cast(Types::DodgeActive))); if (storedMode == Types::AlwaysVisible) { qDebug() << "Loading visibility mode: Always Visible , on startup..."; setMode(Types::AlwaysVisible); } else { connect(&m_timerStartUp, &QTimer::timeout, this, [&]() { auto fMode = static_cast(m_latteView->containment()->config().readEntry("visibility", static_cast(Types::DodgeActive))); qDebug() << "Loading visibility mode:" << fMode << " on startup..."; setMode(fMode); }); connect(m_latteView->containment(), &Plasma::Containment::userConfiguringChanged , this, [&](bool configuring) { if (configuring && m_timerStartUp.isActive()) m_timerStartUp.start(100); }); m_timerStartUp.start(); } connect(m_latteView->containment(), &Plasma::Containment::userConfiguringChanged , this, [&](bool configuring) { if (!configuring) { saveConfig(); } }); } bool VisibilityManager::containsMouse() const { return m_containsMouse; } void VisibilityManager::setContainsMouse(bool contains) { if (m_containsMouse == contains) { return; } m_containsMouse = contains; emit containsMouseChanged(); if (contains && m_mode != Types::AlwaysVisible) { raiseView(true); } } void VisibilityManager::viewEventManager(QEvent *ev) { switch (ev->type()) { case QEvent::Enter: setContainsMouse(true); break; case QEvent::Leave: setContainsMouse(false); updateHiddenState(); break; case QEvent::DragEnter: dragEnter = true; if (m_isHidden) emit mustBeShown(); break; case QEvent::DragLeave: case QEvent::Drop: dragEnter = false; updateHiddenState(); break; case QEvent::Show: wm->setViewExtraFlags(*m_latteView); break; default: break; } } -void VisibilityManager::cleanupFaultyWindows() -{ - foreach (auto key, windows.keys()) { - auto winfo = windows[key]; - - //! garbage windows removing - if (winfo.geometry() == QRect(0, 0, 0, 0)) { - //qDebug() << "Faulty Geometry ::: " << winfo.wid(); - windows.remove(key); - } - } -} - //! KWin Edges Support functions bool VisibilityManager::enableKWinEdges() const { return enableKWinEdgesFromUser; } void VisibilityManager::setEnableKWinEdges(bool enable) { if (enableKWinEdgesFromUser == enable) { return; } enableKWinEdgesFromUser = enable; emit enableKWinEdgesChanged(); updateKWinEdgesSupport(); } void VisibilityManager::updateKWinEdgesSupport() { if (m_mode == Types::AutoHide || m_mode == Types::DodgeActive || m_mode == Types::DodgeAllWindows || m_mode == Types::DodgeMaximized) { if (enableKWinEdgesFromUser) { createEdgeGhostWindow(); } else if (!enableKWinEdgesFromUser) { deleteEdgeGhostWindow(); } } else if (m_mode == Types::AlwaysVisible || m_mode == Types::WindowsGoBelow) { deleteEdgeGhostWindow(); } } void VisibilityManager::createEdgeGhostWindow() { if (!edgeGhostWindow) { edgeGhostWindow = new ScreenEdgeGhostWindow(m_latteView); wm->setViewExtraFlags(*edgeGhostWindow); connect(edgeGhostWindow, &ScreenEdgeGhostWindow::containsMouseChanged, this, [ = ](bool contains) { if (contains) { emit mustBeShown(); } }); connectionsKWinEdges[0] = connect(wm, &WindowSystem::currentActivityChanged, this, [&]() { bool inCurrentLayout = (m_corona->layoutManager()->memoryUsage() == Types::SingleLayout || (m_corona->layoutManager()->memoryUsage() == Types::MultipleLayouts && m_latteView->managedLayout() && !m_latteView->positioner()->inLocationChangeAnimation() && m_latteView->managedLayout()->name() == m_corona->layoutManager()->currentLayoutName())); if (edgeGhostWindow) { if (inCurrentLayout) { wm->setEdgeStateFor(edgeGhostWindow, m_isHidden); } else { wm->setEdgeStateFor(edgeGhostWindow, false); } } }); emit supportsKWinEdgesChanged(); } } void VisibilityManager::deleteEdgeGhostWindow() { if (edgeGhostWindow) { edgeGhostWindow->deleteLater(); edgeGhostWindow = nullptr; for (auto &c : connectionsKWinEdges) { disconnect(c); } emit supportsKWinEdgesChanged(); } } //! END: VisibilityManager implementation } } diff --git a/app/view/visibilitymanager.h b/app/view/visibilitymanager.h index 64228ea2..d2bba331 100644 --- a/app/view/visibilitymanager.h +++ b/app/view/visibilitymanager.h @@ -1,188 +1,183 @@ /* * Copyright 2016 Smith AR * Michail Vourlakos * * This file is part of Latte-Dock * * Latte-Dock is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * Latte-Dock is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef VISIBILITYMANAGER_H #define VISIBILITYMANAGER_H // local #include "../plasma/quick/containmentview.h" #include "../schemecolors.h" #include "../wm/abstractwindowinterface.h" #include "../wm/windowinfowrap.h" #include "../../liblatte2/types.h" // Qt #include #include // Plasma #include namespace Latte { class Corona; class View; namespace ViewPart { class ScreenEdgeGhostWindow; } } namespace Latte { namespace ViewPart { class VisibilityManager : public QObject { Q_OBJECT Q_PROPERTY(Latte::Types::Visibility mode READ mode WRITE setMode NOTIFY modeChanged) Q_PROPERTY(bool raiseOnDesktop READ raiseOnDesktop WRITE setRaiseOnDesktop NOTIFY raiseOnDesktopChanged) Q_PROPERTY(bool raiseOnActivity READ raiseOnActivity WRITE setRaiseOnActivity NOTIFY raiseOnActivityChanged) Q_PROPERTY(bool isHidden READ isHidden WRITE setIsHidden NOTIFY isHiddenChanged) Q_PROPERTY(bool blockHiding READ blockHiding WRITE setBlockHiding NOTIFY blockHidingChanged) Q_PROPERTY(bool containsMouse READ containsMouse NOTIFY containsMouseChanged) //! KWin Edges Support Options Q_PROPERTY(bool enableKWinEdges READ enableKWinEdges WRITE setEnableKWinEdges NOTIFY enableKWinEdgesChanged) Q_PROPERTY(bool supportsKWinEdges READ supportsKWinEdges NOTIFY supportsKWinEdgesChanged) Q_PROPERTY(int timerShow READ timerShow WRITE setTimerShow NOTIFY timerShowChanged) Q_PROPERTY(int timerHide READ timerHide WRITE setTimerHide NOTIFY timerHideChanged) public: explicit VisibilityManager(PlasmaQuick::ContainmentView *view); virtual ~VisibilityManager(); Latte::Types::Visibility mode() const; void setMode(Latte::Types::Visibility mode); void applyActivitiesToHiddenWindows(const QStringList &activities); bool raiseOnDesktop() const; void setRaiseOnDesktop(bool enable); bool raiseOnActivity() const; void setRaiseOnActivity(bool enable); bool isHidden() const; void setIsHidden(bool isHidden); bool blockHiding() const; void setBlockHiding(bool blockHiding); bool containsMouse() const; int timerShow() const; void setTimerShow(int msec); int timerHide() const; void setTimerHide(int msec); bool intersects(const WindowInfoWrap &winfo); //! KWin Edges Support functions bool enableKWinEdges() const; void setEnableKWinEdges(bool enable); bool supportsKWinEdges() const; //! called for windowTracker to reset values void activeWindowDraggingStarted(); signals: void mustBeShown(); void mustBeHide(); void modeChanged(); void raiseOnDesktopChanged(); void raiseOnActivityChanged(); void isHiddenChanged(); void blockHidingChanged(); void containsMouseChanged(); void timerShowChanged(); void timerHideChanged(); - void touchingWindowSchemeChanged(); //! KWin Edges Support signals void enableKWinEdgesChanged(); void supportsKWinEdgesChanged(); private slots: void saveConfig(); void restoreConfig(); private: void setContainsMouse(bool contains); void raiseView(bool raise); void raiseViewTemporarily(); void updateHiddenState(); - //! the notification window is not sending a remove signal and creates windows of geometry (0x0 0,0), - //! this is a garbage collector to collect such windows in order to not break the windows array validity. - void cleanupFaultyWindows(); //! KWin Edges Support functions void createEdgeGhostWindow(); void deleteEdgeGhostWindow(); void updateKWinEdgesSupport(); void setViewGeometry(const QRect &rect); void windowAdded(WindowId id); void dodgeActive(WindowId id); void dodgeMaximized(WindowId id); - void dodgeWindows(WindowId id); - void checkAllWindows(); void updateStrutsBasedOnLayoutsAndActivities(); void viewEventManager(QEvent *ev); +private slots: + void dodgeAllWindows(); + private: AbstractWindowInterface *wm; Types::Visibility m_mode{Types::None}; std::array connections; - QMap windows; QTimer m_timerShow; QTimer m_timerHide; - QTimer m_timerCheckWindows; QTimer m_timerStartUp; QRect m_viewGeometry; bool m_isHidden{false}; bool dragEnter{false}; bool m_blockHiding{false}; bool m_containsMouse{false}; bool raiseTemporarily{false}; bool raiseOnDesktopChange{false}; bool raiseOnActivityChange{false}; bool hideNow{false}; //! KWin Edges bool enableKWinEdgesFromUser{true}; std::array connectionsKWinEdges; ScreenEdgeGhostWindow *edgeGhostWindow{nullptr}; Latte::Corona *m_corona{nullptr}; Latte::View *m_latteView{nullptr}; }; } } #endif // VISIBILITYMANAGER_H diff --git a/app/view/windowstracker.cpp b/app/view/windowstracker.cpp index 294986c1..30dad31f 100644 --- a/app/view/windowstracker.cpp +++ b/app/view/windowstracker.cpp @@ -1,330 +1,354 @@ /* * Copyright 2019 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 "windowstracker.h" // local #include "positioner.h" #include "view.h" #include "../lattecorona.h" #include "../../liblatte2/types.h" namespace Latte { namespace ViewPart { WindowsTracker::WindowsTracker(Latte::View *parent) : QObject(parent), m_latteView(parent) { qDebug() << "WindowsTracker creating..."; m_corona = qobject_cast(m_latteView->corona()); m_wm = m_corona->wm(); } WindowsTracker::~WindowsTracker() { qDebug() << "WindowsTracker removing..."; } +bool WindowsTracker::activeWindowTouching() const +{ + return m_activeWindowIsTouchingFlag; +} + +void WindowsTracker::setActiveWindowTouching(bool activeTouching) +{ + if (m_activeWindowIsTouchingFlag == activeTouching) { + return; + } + + m_activeWindowIsTouchingFlag = activeTouching; + emit activeWindowTouchingChanged(); +} + bool WindowsTracker::existsWindowMaximized() const { return m_windowIsMaximizedFlag; } void WindowsTracker::setExistsWindowMaximized(bool windowMaximized) { if (m_windowIsMaximizedFlag == windowMaximized) { return; } m_windowIsMaximizedFlag = windowMaximized; - emit existsWindowMaximizedChanged(); } bool WindowsTracker::existsWindowTouching() const { return m_windowIsTouchingFlag; } void WindowsTracker::setExistsWindowTouching(bool windowTouching) { if (m_windowIsTouchingFlag == windowTouching) { return; } m_windowIsTouchingFlag = windowTouching; - emit existsWindowTouchingChanged(); } SchemeColors *WindowsTracker::touchingWindowScheme() const { return m_touchingScheme; } void WindowsTracker::setTouchingWindowScheme(SchemeColors *scheme) { if (m_touchingScheme == scheme) { return; } m_touchingScheme = scheme; emit touchingWindowSchemeChanged(); } bool WindowsTracker::enabled() const { return m_enabled; } void WindowsTracker::setEnabled(bool active) { if (m_enabled == active) { return; } m_enabled = active; if (m_enabled) { m_windows.clear(); for (const auto &wid : m_wm->windows()) { m_windows.insert(wid, m_wm->requestInfo(wid)); } m_connections[0] = connect(m_corona, &Plasma::Corona::availableScreenRectChanged, this, &WindowsTracker::updateAvailableScreenGeometry); m_connections[1] = connect(m_wm, &WindowSystem::windowChanged, this, [&](WindowId wid) { m_windows[wid] = m_wm->requestInfo(wid); updateFlags(); }); m_connections[2] = connect(m_wm, &WindowSystem::windowRemoved, this, [&](WindowId wid) { m_windows.remove(wid); }); m_connections[3] = connect(m_wm, &WindowSystem::windowAdded, this, [&](WindowId wid) { m_windows.insert(wid, m_wm->requestInfo(wid)); updateFlags(); }); m_connections[4] = connect(m_wm, &WindowSystem::activeWindowChanged, this, [&](WindowId wid) { if (m_windows.contains(m_lastActiveWindowWid)) { m_windows[m_lastActiveWindowWid] = m_wm->requestInfo(m_lastActiveWindowWid); } m_windows[wid] = m_wm->requestInfo(wid); m_lastActiveWindowWid = wid; updateFlags(); }); m_connections[5] = connect(m_wm, &WindowSystem::currentDesktopChanged, this, [&] { updateFlags(); }); m_connections[6] = connect(m_wm, &WindowSystem::currentActivityChanged, this, [&] { updateFlags(); }); updateAvailableScreenGeometry(); updateFlags(); } else { // clear mode for (auto &c : m_connections) { disconnect(c); } m_windows.clear(); + + setActiveWindowTouching(false); + setExistsWindowMaximized(false); + setExistsWindowTouching(false); } emit enabledChanged(); } void WindowsTracker::updateAvailableScreenGeometry() { if (!m_latteView || !m_latteView->containment()) { return; } int currentScrId = m_latteView->positioner()->currentScreenId(); QRect tempAvailableScreenGeometry = m_corona->availableScreenRectWithCriteria(currentScrId, {Types::AlwaysVisible}, {}); if (tempAvailableScreenGeometry != m_availableScreenGeometry) { m_availableScreenGeometry = tempAvailableScreenGeometry; updateFlags(); } } void WindowsTracker::updateFlags() { + bool foundActiveTouch{false}; bool foundTouch{false}; bool foundMaximized{false}; //! the notification window is not sending a remove signal and creates windows of geometry (0x0 0,0), //! maybe a garbage collector here is a good idea!!! bool existsFaultyWindow{false}; WindowId maxWinId; + WindowId activeTouchWinId; WindowId touchWinId; for (const auto &winfo : m_windows) { if (isMaximizedInCurrentScreen(winfo)) { foundMaximized = true; maxWinId = winfo.wid(); } - if (winfo.isActive() && (isTouchingPanelEdge(winfo) || (m_latteView->visibility()->intersects(winfo)))) { - foundTouch = true; - touchWinId = winfo.wid(); + if ((isTouchingPanelEdge(winfo) || (m_latteView->visibility()->intersects(winfo)))) { + if (winfo.isActive()) { + foundActiveTouch = true; + activeTouchWinId = winfo.wid(); + } else { + foundTouch = true; + touchWinId = winfo.wid(); + } } if (!existsFaultyWindow && winfo.geometry() == QRect(0, 0, 0, 0)) { existsFaultyWindow = true; } //qDebug() << "window geometry ::: " << winfo.geometry(); } if (existsFaultyWindow) { cleanupFaultyWindows(); } + setActiveWindowTouching(foundActiveTouch); setExistsWindowMaximized(foundMaximized); setExistsWindowTouching(foundTouch); //! update color scheme for touching window - if (foundTouch) { - //! first the touching one because that would mean it is active - setTouchingWindowScheme(m_wm->schemeForWindow(touchWinId)); + if (foundActiveTouch) { + setTouchingWindowScheme(m_wm->schemeForWindow(activeTouchWinId)); } else if (foundMaximized) { setTouchingWindowScheme(m_wm->schemeForWindow(maxWinId)); } else { setTouchingWindowScheme(nullptr); } } bool WindowsTracker::isMaximizedInCurrentScreen(const WindowInfoWrap &winfo) { //! updated implementation to identify the screen that the maximized window is present //! in order to avoid: https://bugs.kde.org/show_bug.cgi?id=397700 if (winfo.isValid() && !winfo.isMinimized() && m_wm->isOnCurrentDesktop(winfo.wid()) && m_wm->isOnCurrentActivity(winfo.wid())) { if (winfo.isMaximized() && m_availableScreenGeometry.contains(winfo.geometry().center())) { return true; } } return false; } bool WindowsTracker::isTouchingPanelEdge(const WindowInfoWrap &winfo) { if (winfo.isValid() && !winfo.isMinimized() && m_wm->isOnCurrentDesktop(winfo.wid()) && m_wm->isOnCurrentActivity(winfo.wid())) { bool touchingPanelEdge{false}; QRect screenGeometry = m_latteView->screenGeometry(); bool inCurrentScreen{screenGeometry.contains(winfo.geometry().topLeft()) || screenGeometry.contains(winfo.geometry().bottomRight())}; if (inCurrentScreen) { if (m_latteView->location() == Plasma::Types::TopEdge) { touchingPanelEdge = (winfo.geometry().y() == m_availableScreenGeometry.y()); } else if (m_latteView->location() == Plasma::Types::BottomEdge) { touchingPanelEdge = (winfo.geometry().bottom() == m_availableScreenGeometry.bottom()); } else if (m_latteView->location() == Plasma::Types::LeftEdge) { touchingPanelEdge = (winfo.geometry().x() == m_availableScreenGeometry.x()); } else if (m_latteView->location() == Plasma::Types::RightEdge) { touchingPanelEdge = (winfo.geometry().right() == m_availableScreenGeometry.right()); } } return touchingPanelEdge; } return false; } void WindowsTracker::cleanupFaultyWindows() { foreach (auto key, m_windows.keys()) { auto winfo = m_windows[key]; //! garbage windows removing if (winfo.geometry() == QRect(0, 0, 0, 0)) { //qDebug() << "Faulty Geometry ::: " << winfo.wid(); m_windows.remove(key); } } } //! Window Functions void WindowsTracker::setWindowOnActivities(QWindow &window, const QStringList &activities) { m_wm->setWindowOnActivities(window, activities); } void WindowsTracker::requestToggleMaximizeForActiveWindow() { WindowInfoWrap actInfo = m_wm->requestInfoActive(); //active window can be toggled only when it is in the same screen if (actInfo.isValid() && !actInfo.geometry().isNull() && m_latteView->screenGeometry().contains(actInfo.geometry().center())) { m_wm->requestToggleMaximized(actInfo.wid()); } } void WindowsTracker::requestMoveActiveWindow(int localX, int localY) { WindowInfoWrap actInfo = m_wm->requestInfoActive(); //active window can be dragged only when it is in the same screen if (actInfo.isValid() && !actInfo.geometry().isNull() && m_latteView->screenGeometry().contains(actInfo.geometry().center())) { QPoint globalPoint{m_latteView->x() + localX, m_latteView->y() + localY}; m_wm->requestMoveWindow(actInfo.wid(), globalPoint); //! This timer is needed because otherwise the mouse position //! in the dragged window changes to TopLeft corner QTimer::singleShot(250, this, [&, actInfo, globalPoint]() { m_wm->releaseMouseEventFor(m_latteView->winId()); }); m_latteView->visibility()->activeWindowDraggingStarted(); } } bool WindowsTracker::activeWindowCanBeDragged() { WindowInfoWrap actInfo = m_wm->requestInfoActive(); //active window can be dragged only when it is in the same screen if (actInfo.isValid() && !actInfo.geometry().isNull() && m_latteView->screenGeometry().contains(actInfo.geometry().center())) { return m_wm->windowCanBeDragged(actInfo.wid()); } return false; } } } diff --git a/app/view/windowstracker.h b/app/view/windowstracker.h index 86972389..4eb2d643 100644 --- a/app/view/windowstracker.h +++ b/app/view/windowstracker.h @@ -1,108 +1,113 @@ /* * Copyright 2019 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 WINDOWSTRACKER_H #define WINDOWSTRACKER_H // local #include "../schemecolors.h" #include "../wm/abstractwindowinterface.h" #include "../wm/windowinfowrap.h" // Qt #include namespace Latte{ class AbstractWindowInterface; class Corona; class View; } namespace Latte { namespace ViewPart { class WindowsTracker : public QObject { Q_OBJECT Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) + Q_PROPERTY(bool activeWindowTouching READ activeWindowTouching NOTIFY activeWindowTouchingChanged) Q_PROPERTY(bool existsWindowMaximized READ existsWindowMaximized NOTIFY existsWindowMaximizedChanged) Q_PROPERTY(bool existsWindowTouching READ existsWindowTouching NOTIFY existsWindowTouchingChanged) Q_PROPERTY(SchemeColors *touchingWindowScheme READ touchingWindowScheme NOTIFY touchingWindowSchemeChanged) public: explicit WindowsTracker(Latte::View *parent); virtual ~WindowsTracker(); bool enabled() const; void setEnabled(bool active); + bool activeWindowTouching() const; bool existsWindowMaximized() const; bool existsWindowTouching() const; SchemeColors *touchingWindowScheme() const; void setWindowOnActivities(QWindow &window, const QStringList &activities); signals: void enabledChanged(); + void activeWindowTouchingChanged(); void existsWindowMaximizedChanged(); void existsWindowTouchingChanged(); void touchingWindowSchemeChanged(); public slots: Q_INVOKABLE void requestToggleMaximizeForActiveWindow(); Q_INVOKABLE void requestMoveActiveWindow(int localX, int localY); Q_INVOKABLE bool activeWindowCanBeDragged(); private: + void setActiveWindowTouching(bool activeTouching); void setExistsWindowMaximized(bool windowMaximized); void setExistsWindowTouching(bool windowTouching); void setTouchingWindowScheme(SchemeColors *scheme); void updateAvailableScreenGeometry(); void updateFlags(); //! the notification window is not sending a remove signal and creates windows of geometry (0x0 0,0), //! this is a garbage collector to collect such windows in order to not break the windows array validity. void cleanupFaultyWindows(); bool isMaximizedInCurrentScreen(const WindowInfoWrap &winfo); bool isTouchingPanelEdge(const WindowInfoWrap &winfo); private: bool m_enabled{false}; + bool m_activeWindowIsTouchingFlag{false}; bool m_windowIsTouchingFlag{false}; bool m_windowIsMaximizedFlag{false}; QRect m_availableScreenGeometry; WindowId m_lastActiveWindowWid; std::array m_connections; QMap m_windows; SchemeColors *m_touchingScheme{nullptr}; Latte::AbstractWindowInterface *m_wm; Latte::Corona *m_corona{nullptr}; Latte::View *m_latteView{nullptr}; }; } } #endif diff --git a/containment/package/contents/ui/VisibilityManager.qml b/containment/package/contents/ui/VisibilityManager.qml index 2a752fa6..3e01197a 100644 --- a/containment/package/contents/ui/VisibilityManager.qml +++ b/containment/package/contents/ui/VisibilityManager.qml @@ -1,656 +1,657 @@ /* * 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.2 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.themePanelThickness >= 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: latteView property:"maxThickness" //! prevents updating window geometry during closing window in wayland and such fixes a crash when: latteView && !inTempHiding && !inForceHiding value: thicknessZoomOriginal } Binding{ target: latteView property:"normalThickness" when: latteView value: thicknessNormalOriginal } Binding{ target: latteView property: "behaveAsPlasmaPanel" when: latteView value: root.editMode ? false : root.behaveAsPlasmaPanel } Binding{ target: latteView property: "fontPixelSize" when: theme value: theme.defaultFont.pixelSize } Binding{ target: latteView property:"inEditMode" when: latteView value: root.editMode } Binding{ target: latteView property: "maxLength" when: latteView value: root.editMode ? 1 : plasmoid.configuration.maxLength/100 } Binding{ target: latteView property: "offset" when: latteView value: plasmoid.configuration.offset } Binding{ target: latteView property: "alignment" when: latteView value: root.panelAlignment } Binding{ target: latteView && latteView.effects ? latteView.effects : null property: "backgroundOpacity" when: latteView && latteView.effects value: root.currentPanelTransparency } Binding{ target: latteView && latteView.effects ? latteView.effects : null property: "drawEffects" when: latteView && latteView.effects value: Latte.WindowSystem.compositingActive && !editModeVisual.inEditMode && (((root.blurEnabled && root.useThemePanel) || (root.blurEnabled && root.forceSolidPanel && latteView.windowsTracker.existsWindowMaximized && Latte.WindowSystem.compositingActive) || (root.blurEnabled && root.forcePanelForDistortedBackground && Latte.WindowSystem.compositingActive)) && (!root.inStartup || inForceHiding || inTempHiding)) } Binding{ target: latteView && latteView.effects ? latteView.effects : null property: "drawShadows" when: latteView && latteView.effects value: root.drawShadowsExternal && (!root.inStartup || inForceHiding || inTempHiding) } Binding{ target: latteView && latteView.effects ? latteView.effects : null property:"innerShadow" when: latteView && latteView.effects value: { if (editModeVisual.editAnimationEnded && !root.behaveAsPlasmaPanel) { return root.editShadow; } else { return root.panelShadow; } } } Binding{ target: latteView && latteView.windowsTracker ? latteView.windowsTracker : null property: "enabled" when: latteView && latteView.windowsTracker - value: (root.backgroundOnlyOnMaximized - || plasmoid.configuration.solidBackgroundForMaximized - || root.disablePanelShadowMaximized) - && Latte.WindowSystem.compositingActive + value: (latteView.visibility && latteView.visibility.mode === Latte.Types.DodgeAllWindows) + || ((root.backgroundOnlyOnMaximized + || plasmoid.configuration.solidBackgroundForMaximized + || root.disablePanelShadowMaximized) + && Latte.WindowSystem.compositingActive) } Connections{ target:root onPanelShadowChanged: updateMaskArea(); onPanelThickMarginHighChanged: updateMaskArea(); } Connections{ target: universalLayoutManager onCurrentLayoutIsSwitching: { if (Latte.WindowSystem.compositingActive && latteView && latteView.managedLayout && latteView.managedLayout.name === layoutName) { manager.inTempHiding = true; manager.inForceHiding = true; root.clearZoom(); manager.slotMustBeHide(); } } } onNormalStateChanged: { if (normalState) { root.updateAutomaticIconSize(); root.updateSizeForAppletsInFill(); } } onThicknessZoomOriginalChanged: { updateMaskArea(); } function slotContainsMouseChanged() { if(latteView.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 && !latteView.visibility.blockHiding && !latteView.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; latteView.positioner.hideDockDuringLocationChangeFinished(); } ///test maskArea function updateMaskArea() { if (!latteView || blockUpdateMask) { return; } var localX = 0; var localY = 0; normalState = ((root.animationsNeedBothAxis === 0) && (root.animationsNeedLength === 0)) || (latteView.visibility.isHidden && !latteView.visibility.containsMouse && root.animationsNeedThickness == 0); // debug maskArea criteria if (debugMagager) { console.log(root.animationsNeedBothAxis + ", " + root.animationsNeedLength + ", " + root.animationsNeedThickness + ", " + latteView.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.Types.Justify ? layoutsContainer.width + space : layoutsContainer.mainLayout.width + space; } else { tempLength = plasmoid.configuration.panelPosition === Latte.Types.Justify ? layoutsContainer.height + space : layoutsContainer.mainLayout.height + space; } } tempThickness = thicknessNormal; if (root.animationsNeedThickness > 0) { tempThickness = Latte.WindowSystem.compositingActive ? thicknessZoom : thicknessNormal; } if (latteView.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 = latteView.visibility.isHidden && latteView.visibility.supportsKWinEdges ? latteView.height + tempThickness : latteView.height - tempThickness; } else if (plasmoid.location === PlasmaCore.Types.TopEdge) { localY = latteView.visibility.isHidden && latteView.visibility.supportsKWinEdges ? -tempThickness : 0; } if (noCompositingEdit) { localX = 0; } else if (plasmoid.configuration.panelPosition === Latte.Types.Justify) { localX = (latteView.width/2) - tempLength/2 + root.offset; } else if (root.panelAlignment === Latte.Types.Left) { localX = root.offset; } else if (root.panelAlignment === Latte.Types.Center) { localX = (latteView.width/2) - tempLength/2 + root.offset; } else if (root.panelAlignment === Latte.Types.Right) { localX = latteView.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 = latteView.visibility.isHidden && latteView.visibility.supportsKWinEdges ? -tempThickness : 0; } else if (plasmoid.location === PlasmaCore.Types.RightEdge) { localX = latteView.visibility.isHidden && latteView.visibility.supportsKWinEdges ? latteView.width + tempThickness : latteView.width - tempThickness; } if (noCompositingEdit) { localY = 0; } else if (plasmoid.configuration.panelPosition === Latte.Types.Justify) { localY = (latteView.height/2) - tempLength/2 + root.offset; } else if (root.panelAlignment === Latte.Types.Top) { localY = root.offset; } else if (root.panelAlignment === Latte.Types.Center) { localY = (latteView.height/2) - tempLength/2 + root.offset; } else if (root.panelAlignment === Latte.Types.Bottom) { localY = latteView.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 (latteView.visibility.isHidden && !slidingAnimationAutoHiddenOut.running ) { tempThickness = thicknessAutoHidden; } else if (root.animationsNeedThickness > 0) { tempThickness = thicknessZoomOriginal; } } else{ //use all thickness space if (latteView.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,latteView.width - tempThickness); else if(plasmoid.location === PlasmaCore.Types.BottomEdge) localY = Math.max(0,latteView.height - tempThickness); } } // end of compositing calculations var maskArea = latteView.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 (!latteView.visibility.isHidden || !latteView.visibility.supportsKWinEdges) { localX = latteView.effects.rect.x; localY = latteView.effects.rect.y; } else { if (plasmoid.location === PlasmaCore.Types.BottomEdge) { localX = latteView.effects.rect.x; localY = latteView.effects.rect.y+dock.effects.rect.height+thicknessAutoHidden; } else if (plasmoid.location === PlasmaCore.Types.TopEdge) { localX = latteView.effects.rect.x; localY = latteView.effects.rect.y - thicknessAutoHidden; } else if (plasmoid.location === PlasmaCore.Types.LeftEdge) { localX = latteView.effects.rect.x - thicknessAutoHidden; localY = latteView.effects.rect.y; } else if (plasmoid.location === PlasmaCore.Types.RightEdge) { localX = latteView.effects.rect.x + latteView.effects.rect.width + 1; localY = latteView.effects.rect.y; } } if (root.isHorizontal) { tempThickness = latteView.effects.rect.height; tempLength = latteView.effects.rect.width; } else { tempThickness = latteView.effects.rect.width; tempLength = latteView.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) { latteView.effects.mask = newMaskArea; } else { if (latteView.behaveAsPlasmaPanel && !root.editMode) { latteView.effects.mask = Qt.rect(0,0,root.width,root.height); } else { latteView.effects.mask = newMaskArea; } } } //console.log("reached updating geometry ::: "+dock.maskArea); if(normalState){ var tempGeometry = Qt.rect(latteView.effects.mask.x, latteView.effects.mask.y, latteView.effects.mask.width, latteView.effects.mask.height); //the shadows size must be removed from the maskArea //before updating the localDockGeometry if ((!latteView.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 = latteView.height - fixedThickness; } else if (plasmoid.location === PlasmaCore.Types.RightEdge) { tempGeometry.x = latteView.width - fixedThickness; } //set the boundaries for latteView local geometry //qBound = qMax(min, qMin(value, max)). tempGeometry.x = Math.max(0, Math.min(tempGeometry.x, latteView.width)); tempGeometry.y = Math.max(0, Math.min(tempGeometry.y, latteView.height)); tempGeometry.width = Math.min(tempGeometry.width, latteView.width); tempGeometry.height = Math.min(tempGeometry.height, latteView.height); } //console.log("update geometry ::: "+tempGeometry); if (!Latte.WindowSystem.compositingActive) { latteView.localGeometry = latteView.effects.rect; } else { latteView.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: latteView ? latteView.effects.mask.x : -1 y: latteView ? latteView.effects.mask.y : -1 height: latteView ? latteView.effects.mask.height : 0 width: latteView ? latteView.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: { latteView.visibility.isHidden = true; } } onStarted: { if (manager.debugMagager) { console.log("hiding animation started..."); } } onStopped: { latteView.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 (!latteView.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 (!latteView.visibility.blockHiding) inSlidingIn = true; if (slidingAnimationAutoHiddenOut.running) { slidingAnimationAutoHiddenOut.stop(); } latteView.visibility.isHidden = false; updateMaskArea(); start(); } } } diff --git a/containment/package/contents/ui/main.qml b/containment/package/contents/ui/main.qml index f02b9ca0..70bbd6fa 100644 --- a/containment/package/contents/ui/main.qml +++ b/containment/package/contents/ui/main.qml @@ -1,1873 +1,1873 @@ /* * 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.Layouts 1.1 import QtQuick.Window 2.2 import QtGraphicalEffects 1.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.kquickcontrolsaddons 2.0 import org.kde.draganddrop 2.0 as DragDrop import org.kde.plasma.plasmoid 2.0 import org.kde.latte 0.2 as Latte import "applet" as Applet import "colorizer" as Colorizer import "../code/LayoutManager.js" as LayoutManager DragDrop.DropArea { id: root objectName: "containmentViewLayout" LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft && !root.isVertical LayoutMirroring.childrenInherit: true //// BEGIN SIGNALS signal clearZoomSignal(); signal separatorsUpdated(); signal signalActivateEntryAtIndex(int entryIndex); signal signalNewInstanceForEntryAtIndex(int entryIndex); signal updateEffectsArea(); signal updateIndexes(); signal updateScale(int delegateIndex, real newScale, real step); //// END SIGNALS ////BEGIN properties property bool debugMode: Qt.application.arguments.indexOf("--graphics")>=0 property bool debugModeSpacers: Qt.application.arguments.indexOf("--spacers")>=0 property bool debugModeTimers: Qt.application.arguments.indexOf("--timers")>=0 property bool debugModeWindow: Qt.application.arguments.indexOf("--with-window")>=0 property bool debugModeOverloadedIcons: Qt.application.arguments.indexOf("--overloaded-icons")>=0 property bool globalDirectRender: false //it is used as a globalDirectRender for all elements in the dock property int directRenderAnimationTime: 0 property bool addLaunchersMessage: false property bool addLaunchersInTaskManager: plasmoid.configuration.addLaunchersInTaskManager // when there are only plasma style task managers the automatic icon size algorithm should better be disabled property bool autoDecreaseIconSize: plasmoid.configuration.autoDecreaseIconSize && !containsOnlyPlasmaTasks && layoutsContainer.fillApplets<=0 property bool backgroundOnlyOnMaximized: plasmoid.configuration.backgroundOnlyOnMaximized property bool behaveAsPlasmaPanel: { if (!latteView || !latteView.visibility) return false; return (visibilityManager.panelIsBiggerFromIconSize && (zoomFactor === 1.0) && (latteView.visibility.mode === Latte.Types.AlwaysVisible || latteView.visibility.mode === Latte.Types.WindowsGoBelow) && (plasmoid.configuration.panelPosition === Latte.Types.Justify) && !(root.solidStylePanel && panelShadowsActive)); } property bool blurEnabled: plasmoid.configuration.blurEnabled && (!root.forceTransparentPanel || root.forcePanelForBusyBackground) //|| (hasExpandedApplet && zoomFactor===1 && plasmoid.configuration.panelSize===100) property bool confirmedDragEntered: false property bool containsOnlyPlasmaTasks: false //this is flag to indicate when from tasks only a plasma based one is found property bool dockContainsMouse: latteView && latteView.visibility ? latteView.visibility.containsMouse : false property bool disablePanelShadowMaximized: plasmoid.configuration.disablePanelShadowForMaximized && Latte.WindowSystem.compositingActive property bool drawShadowsExternal: panelShadowsActive && behaveAsPlasmaPanel && !visibilityManager.inTempHiding property bool editMode: editModeVisual.inEditMode property bool windowIsTouching: latteView && latteView.windowsTracker - && (latteView.windowsTracker.existsWindowMaximized|| latteView.windowsTracker.existsWindowTouching || hasExpandedApplet) + && (latteView.windowsTracker.existsWindowMaximized|| latteView.windowsTracker.activeWindowTouching || hasExpandedApplet) property bool forceSemiTransparentPanel: Latte.WindowSystem.compositingActive && !root.editMode && ((!plasmoid.configuration.solidBackgroundForMaximized && plasmoid.configuration.backgroundOnlyOnMaximized && windowIsTouching) || (plasmoid.configuration.solidBackgroundForMaximized && !plasmoid.configuration.backgroundOnlyOnMaximized && !windowIsTouching)) property bool forceSolidPanel: (plasmoid.configuration.solidBackgroundForMaximized && latteView && latteView.visibility && Latte.WindowSystem.compositingActive && !root.editMode - && (latteView.windowsTracker.existsWindowMaximized || latteView.windowsTracker.existsWindowTouching || hasExpandedApplet + && (latteView.windowsTracker.existsWindowMaximized || latteView.windowsTracker.activeWindowTouching || hasExpandedApplet || showAppletShortcutBadges || showMetaBadge)) || !Latte.WindowSystem.compositingActive property bool forceTransparentPanel: root.backgroundOnlyOnMaximized && latteView && latteView.visibility && Latte.WindowSystem.compositingActive && !root.editMode - && !(latteView.windowsTracker.existsWindowMaximized || latteView.windowsTracker.existsWindowTouching) + && !(latteView.windowsTracker.existsWindowMaximized || latteView.windowsTracker.activeWindowTouching) && !(hasExpandedApplet && zoomFactor===1 && plasmoid.configuration.panelSize===100) property bool forcePanelForBusyBackground: root.forceTransparentPanel && colorizerManager.mustBeShown && colorizerManager.backgroundIsBusy property bool forceColorizer: Latte.WindowSystem.compositingActive && plasmoid.configuration.colorizeTransparentPanels property bool forceColorizeFromActiveWindowScheme: plasmoid.configuration.colorizeFromActiveWindowScheme && !editMode && (latteView && latteView.windowsTracker && latteView.windowsTracker.touchingWindowScheme - && (latteView.windowsTracker.existsWindowMaximized || latteView.windowsTracker.existsWindowTouching) + && (latteView.windowsTracker.existsWindowMaximized || latteView.windowsTracker.activeWindowTouching) && !hasExpandedApplet) property bool maximizedWindowTitleBarBehavesAsPanelBackground: latteView && latteView.visibility && (!plasmoid.configuration.solidBackgroundForMaximized && plasmoid.configuration.backgroundOnlyOnMaximized) && (latteView.visibility.mode === Latte.Types.WindowsGoBelow) && (plasmoid.location === PlasmaCore.Types.TopEdge) && (!useThemePanel || panelTransparency<40) && latteView.windowsTracker.existsWindowMaximized readonly property bool hasExpandedApplet: plasmoid.applets.some(function (item) { return (item.status >= PlasmaCore.Types.NeedsAttentionStatus && item.status !== PlasmaCore.Types.HiddenStatus && item.pluginName !== root.plasmoidName && item.pluginName !== "org.kde.plasma.appmenu" && item.pluginName !== "org.kde.windowappmenu" && item.pluginName !== "org.kde.activeWindowControl"); }) readonly property bool hasUserSpecifiedBackground: (latteView && latteView.managedLayout && latteView.managedLayout.background.startsWith("/")) ? true : false property bool dockIsShownCompletely: !(dockIsHidden || inSlidingIn || inSlidingOut) && !root.editMode property bool immutable: plasmoid.immutable property bool inFullJustify: (plasmoid.configuration.panelPosition === Latte.Types.Justify) && (plasmoid.configuration.maxLength===100) property bool inSlidingIn: visibilityManager ? visibilityManager.inSlidingIn : false property bool inSlidingOut: visibilityManager ? visibilityManager.inSlidingOut : false property bool inStartup: true property bool isHalfShown: false //is used to disable the zoom hovering effect at sliding in-out the dock property bool isHorizontal: plasmoid.formFactor === PlasmaCore.Types.Horizontal property bool isReady: !(dockIsHidden || inSlidingIn || inSlidingOut) property bool isVertical: !isHorizontal property bool isHovered: latteApplet ? ((latteAppletHoveredIndex !== -1) && (layoutsContainer.hoveredIndex !== -1)) //|| wholeArea.containsMouse : (layoutsContainer.hoveredIndex !== -1) //|| wholeArea.containsMouse property bool mouseWheelActions: plasmoid.configuration.mouseWheelActions property bool normalState : false property bool onlyAddingStarup: true //is used for the initialization phase in startup where there aren't removals, this variable provides a way to grow icon size property bool shrinkThickMargins: plasmoid.configuration.shrinkThickMargins property bool showLatteShortcutBadges: false property bool showAppletShortcutBadges: false property bool showMetaBadge: false property int applicationLauncherId: -1 property bool solidStylePanel: Latte.WindowSystem.compositingActive ? plasmoid.configuration.solidPanel : true //FIXME: possibly this is going to be the default behavior, this user choice //has been dropped from the Dock Configuration Window //property bool smallAutomaticIconJumps: plasmoid.configuration.smallAutomaticIconJumps property bool smallAutomaticIconJumps: true property bool userShowPanelBackground: Latte.WindowSystem.compositingActive ? plasmoid.configuration.useThemePanel : true property bool useThemePanel: noApplets === 0 || !Latte.WindowSystem.compositingActive ? true : (plasmoid.configuration.useThemePanel || plasmoid.configuration.solidBackgroundForMaximized) property alias hoveredIndex: layoutsContainer.hoveredIndex property alias directRenderDelayerIsRunning: directRenderDelayerForEnteringTimer.running property int activeIndicator: plasmoid.configuration.activeIndicator property int actionsBlockHiding: 0 //actions that block hiding property int animationsNeedBothAxis:0 //animations need space in both axes, e.g zooming a task property int animationsNeedLength: 0 // animations need length, e.g. adding a task property int animationsNeedThickness: 0 // animations need thickness, e.g. bouncing animation property int animationTime: durationTime*2.8*units.longDuration property int automaticIconSizeBasedSize: -1 //it is not set, this is the defautl //what is the highest icon size based on what icon size is used, screen calculated or user specified property int maxIconSize: proportionIconSize!==-1 ? proportionIconSize : plasmoid.configuration.iconSize property int iconSize: automaticIconSizeBasedSize > 0 && autoDecreaseIconSize ? Math.min(automaticIconSizeBasedSize, root.maxIconSize) : root.maxIconSize property int proportionIconSize: { //icon size based on screen height if ((plasmoid.configuration.proportionIconSize===-1) || !latteView) return -1; return Math.max(16,Math.round(latteView.screenGeometry.height * plasmoid.configuration.proportionIconSize/100/8)*8); } property int iconStep: 8 property int latteAppletPos: -1 property int maxLength: { if (root.isHorizontal) { return behaveAsPlasmaPanel ? width : width * (plasmoid.configuration.maxLength/100) } else { return behaveAsPlasmaPanel ? height : height * (plasmoid.configuration.maxLength/100) } } property int leftClickAction: plasmoid.configuration.leftClickAction property int middleClickAction: plasmoid.configuration.middleClickAction property int hoverAction: plasmoid.configuration.hoverAction property int modifier: plasmoid.configuration.modifier property int modifierClickAction: plasmoid.configuration.modifierClickAction property int modifierClick: plasmoid.configuration.modifierClick property int panelEdgeSpacing: Math.max(panelBoxBackground.lengthMargins, 1.5*appShadowSize) property int panelTransparency: plasmoid.configuration.panelTransparency //user set property int currentPanelTransparency: 0 //application override property bool panelShadowsActive: { if (!userShowPanelBackground) { return false; } if (root.editMode) { return plasmoid.configuration.panelShadows; } if (plasmoid.configuration.panelShadows && root.forcePanelForBusyBackground) { return true; } if (( (plasmoid.configuration.panelShadows && !root.backgroundOnlyOnMaximized) || (plasmoid.configuration.panelShadows && root.backgroundOnlyOnMaximized && !root.forceTransparentPanel)) && !(disablePanelShadowMaximized && latteView.windowsTracker.existsWindowMaximized)) { return true; } if (hasExpandedApplet && zoomFactor===1 && plasmoid.configuration.panelSize===100 && !(root.solidStylePanel && !plasmoid.configuration.panelShadows) ) { return true; } return false; } property int appShadowOpacity: (plasmoid.configuration.shadowOpacity/100) * 255 property int appShadowSize: enableShadows ? (0.4*root.iconSize) * (plasmoid.configuration.shadowSize/100) : 0 property int appShadowSizeOriginal: enableShadows ? (0.4*maxIconSize) * (plasmoid.configuration.shadowSize/100) : 0 property string appChosenShadowColor: { if (plasmoid.configuration.shadowColorType === Latte.Types.ThemeColorShadow) { var strC = String(theme.textColor); return strC.indexOf("#") === 0 ? strC.substr(1) : strC; } else if (plasmoid.configuration.shadowColorType === Latte.Types.UserColorShadow) { return plasmoid.configuration.shadowColor; } // default shadow color return "080808"; } property string appShadowColor: "#" + decimalToHex(appShadowOpacity) + appChosenShadowColor property string appShadowColorSolid: "#" + appChosenShadowColor property int totalPanelEdgeSpacing: 0 //this is set by PanelBox //FIXME: this is not needed any more probably property int previousAllTasks: -1 //is used to forbid updateAutomaticIconSize when hovering property int offset: { /*if (behaveAsPlasmaPanel) { return 0; }*/ if (root.isHorizontal) { return width * (plasmoid.configuration.offset/100); } else { height * (plasmoid.configuration.offset/100) } } //center the layout correctly when the user uses an offset property int offsetFixed: (offset===0 || panelAlignment === Latte.Types.Center || plasmoid.configuration.panelPosition === Latte.Types.Justify)? offset : offset+panelMarginLength/2+totalPanelEdgeSpacing/2 property int realSize: iconSize + iconMargin property int realPanelSize: 0 property int realPanelLength: 0 property int realPanelThickness: 0 //this is set by the PanelBox property int panelThickMarginBase: 0 property int panelThickMarginHigh: 0 property int panelMarginLength: 0 property int panelShadow: 0 //shadowsSize property int editShadow: { if (!Latte.WindowSystem.compositingActive) { return 0; } else if (latteView && latteView.screenGeometry) { return (latteView.screenGeometry.height/90); } else { return 7; } } property int themePanelThickness: { //root.statesLineSize + root.iconSize + root.iconMargin + 1 var panelBase = root.statesLineSize + root.panelThickMarginHigh; var margin = latteApplet ? thickMargin : 0; var maxPanelSize = (root.statesLineSize + iconSize + margin + 1) - panelBase; var percentage = Latte.WindowSystem.compositingActive ? plasmoid.configuration.panelSize/100 : 1; return Math.max(panelBase, panelBase + percentage*maxPanelSize); } //decouple iconMargin which now is used only for length calculations with thickMargins //which are used for thickness calculations property int thickMarginBase: { if (shrinkThickMargins) { return 0; } else { return Math.ceil(0.06 * iconSize); } } property int thickMarginHigh: { var minimum = 2; if (shrinkThickMargins) { if (behaveAsPlasmaPanel){ return (reverseLinesPosition ? Math.max(root.statesLineSize/2, 1) : minimum); } else { return Math.max(minimum, 0.5 * appShadowSize); } } else { if (behaveAsPlasmaPanel) { return (reverseLinesPosition ? Math.max(root.statesLineSize, 4) : 4); } else { return Math.max( Math.ceil(0.06 * iconSize), 0.5 * appShadowSize); } } } property int thickMargin: thickMarginBase + thickMarginHigh //it is used in order to not break the calculations for the thickness placement //especially in automatic icon sizes calculations property int thickMarginOriginal: Math.ceil(0.06 * maxIconSize + Math.max( Math.ceil(0.06 * maxIconSize), 0.5 * appShadowSizeOriginal)) //! iconMargin from configuration is a percentage. The calculation provides a length //! for that value between 0.04 - 0.5 of iconSize, this way 100% iconMargin means //! equal to the iconSize property int iconMargin: Math.ceil( ((0.5 * (plasmoid.configuration.iconMargin))/100) * iconSize) property int statesLineSize: (latteApplet && !(root.showWindowsOnlyFromLaunchers && root.activeIndicator === Latte.Types.NoneIndicator)) || (activeIndicator !== Latte.Types.NoneIndicator) ? Math.ceil( root.iconSize/13 ) : 0 ///FIXME: I can't remember why this is needed, maybe for the anchorings!!! In order for the Double Layout to not mess the anchorings... //property int layoutsContainer.mainLayoutPosition: !plasmoid.immutable ? Latte.Types.Center : (root.isVertical ? Latte.Types.Top : Latte.Types.Left) //property int panelAlignment: plasmoid.configuration.panelPosition !== Latte.Types.Justify ? plasmoid.configuration.panelPosition : layoutsContainer.mainLayoutPosition property int panelAlignment: !root.editMode ? plasmoid.configuration.panelPosition : ( plasmoid.configuration.panelPosition === Latte.Types.Justify ? Latte.Types.Center : plasmoid.configuration.panelPosition ) property real zoomFactor: (Latte.WindowSystem.compositingActive && durationTime>0) ? ( 1 + (plasmoid.configuration.zoomLevel / 20) ) : 1 readonly property string plasmoidName: "org.kde.latte.plasmoid" property var badgesForActivate: { if (!shortcutsEngine) { return ['1','2','3','4','5','6','7','8','9','0', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.']; } return shortcutsEngine.badgesForActivate; } property var iconsArray: [16, 22, 32, 48, 64, 96, 128, 256] property Item dragOverlay property Item toolBox property Item latteAppletContainer property Item latteApplet property Item parabolicManager: _parabolicManager property QtObject latteView: null property QtObject shortcutsEngine: null property QtObject themeExtended: null property QtObject universalSettings: null property QtObject universalLayoutManager: null property QtObject managedLayout: latteView && latteView.managedLayout ? latteView.managedLayout : null // TO BE DELETED, if not needed: property int counter:0; ///BEGIN properties provided to Latte Plasmoid //shadows for applets, it should be removed as the appleitems don't need it any more property bool enableShadows: plasmoid.configuration.shadows || (root.forceTransparentPanel && plasmoid.configuration.shadows>0) property bool dockIsHidden: latteView ? latteView.visibility.isHidden : true property bool groupTasksByDefault: plasmoid.configuration.groupTasksByDefault property bool dotsOnActive: plasmoid.configuration.dotsOnActive property bool reverseLinesPosition: !latteApplet && plasmoid.configuration.panelSize===100 ? !plasmoid.configuration.reverseLinesPosition : plasmoid.configuration.reverseLinesPosition property bool showGlow: plasmoid.configuration.showGlow || plasmoid.configuration.glowOption!==Latte.Types.GlowNone property bool glow3D: plasmoid.configuration.glow3D property bool showInfoBadge: plasmoid.configuration.showInfoBadge property bool showProgressBadge: plasmoid.configuration.showProgressBadge property bool showAudioBadge: plasmoid.configuration.showAudioBadge property bool showWindowActions: plasmoid.configuration.showWindowActions property bool showWindowsOnlyFromLaunchers: plasmoid.configuration.showWindowsOnlyFromLaunchers property bool showOnlyCurrentScreen: plasmoid.configuration.showOnlyCurrentScreen property bool showOnlyCurrentDesktop: plasmoid.configuration.showOnlyCurrentDesktop property bool showOnlyCurrentActivity: plasmoid.configuration.showOnlyCurrentActivity property bool threeColorsWindows: plasmoid.configuration.threeColorsWindows property bool titleTooltips: plasmoid.configuration.titleTooltips property bool unifiedGlobalShortcuts: plasmoid.configuration.unifiedGlobalShortcuts readonly property bool hasInternalSeparator: latteApplet ? latteApplet.hasInternalSeparator : false property int activeIndicatorType: plasmoid.configuration.activeIndicatorType property int animationStep: { if (!universalSettings || universalSettings.mouseSensitivity === Latte.Types.HighSensitivity) { return 1; } else if (universalSettings.mouseSensitivity === Latte.Types.MediumSensitivity) { return Math.max(3, root.iconSize / 18); } else if (universalSettings.mouseSensitivity === Latte.Types.LowSensitivity) { return Math.max(5, root.iconSize / 10); } } property int glowOption: plasmoid.configuration.glowOption property real glowOpacity: plasmoid.configuration.glowOpacity/100 property int latteAppletHoveredIndex: latteApplet ? latteApplet.hoveredIndex : -1 property int launchersGroup: plasmoid.configuration.launchersGroup property int tasksCount: latteApplet ? latteApplet.tasksCount : 0 property real durationTime: { if ((latteView && latteView.effects && latteView.effects.animationsBlocked) || !Latte.WindowSystem.compositingActive) { return 0; } if (plasmoid.configuration.durationTime === 0 || plasmoid.configuration.durationTime === 2 ) return plasmoid.configuration.durationTime; if (plasmoid.configuration.durationTime === 1) return 1.65; else if (plasmoid.configuration.durationTime === 3) return 2.35; return 2; } property rect screenGeometry: latteView ? latteView.screenGeometry : plasmoid.screenGeometry readonly property color minimizedDotColor: colorizerManager.minimizedDotColor ///END properties from latteApplet /* Layout.preferredWidth: plasmoid.immutable ? (plasmoid.configuration.panelPosition === Latte.Types.Justify ? layoutsContainer.width + 0.5*iconMargin : layoutsContainer.mainLayout.width + iconMargin) : Screen.width //on unlocked state use the maximum Layout.preferredHeight: plasmoid.immutable ? (plasmoid.configuration.panelPosition === Latte.Types.Justify ? layoutsContainer.height + 0.5*iconMargin : layoutsContainer.mainLayout.height + iconMargin) : Screen.height //on unlocked state use the maximum*/ Plasmoid.backgroundHints: PlasmaCore.Types.NoBackground //// BEGIN properties in functions property int noApplets: { var count1 = 0; var count2 = 0; count1 = layoutsContainer.mainLayout.children.length; var tempLength = layoutsContainer.mainLayout.children.length; for (var i=tempLength-1; i>=0; --i) { var applet = layoutsContainer.mainLayout.children[i]; if (applet && (applet === dndSpacer || applet === lastSpacer || applet.isInternalViewSplitter)) count1--; } count2 = layoutsContainer.endLayout.children.length; tempLength = layoutsContainer.endLayout.children.length; for (var i=tempLength-1; i>=0; --i) { var applet = layoutsContainer.endLayout.children[i]; if (applet && (applet === dndSpacer || applet === lastSpacer || applet.isInternalViewSplitter)) count2--; } return (count1 + count2); } ///The index of user's current icon size property int currentIconIndex:{ for(var i=iconsArray.length-1; i>=0; --i){ if(iconsArray[i] === iconSize){ return i; } } return 3; } //// END properties in functions ////////////////END properties //// BEGIN OF Behaviors Behavior on iconMargin { NumberAnimation { duration: 0.8 * root.animationTime easing.type: Easing.OutCubic } } Behavior on iconSize { enabled: !(root.editMode && root.behaveAsPlasmaPanel) NumberAnimation { duration: 0.8 * root.animationTime onRunningChanged: { if (!running) { delayUpdateMaskArea.start(); } } } } Behavior on offset { enabled: editModeVisual.plasmaEditMode NumberAnimation { id: offsetAnimation duration: 0.8 * root.animationTime easing.type: Easing.OutCubic } } //// END OF Behaviors //////////////START OF CONNECTIONS onContainsOnlyPlasmaTasksChanged: updateAutomaticIconSize(); onEditModeChanged: { if (editMode) { visibilityManager.updateMaskArea(); updateAutomaticIconSize(); clearZoom(); } else { updateAutomaticIconSize(); layoutsContainer.updateSizeForAppletsInFill(); } updateLayouts(); //! This is used in case the dndspacer has been left behind //! e.g. the user drops a folder and a context menu is appearing //! but the user decides to not make a choice for the applet type if (dndSpacer.parent !== root) { dndSpacer.parent = root; } } onLatteViewChanged: { if (latteView) { latteView.onAddInternalViewSplitter.connect(addInternalViewSplitters); latteView.onRemoveInternalViewSplitter.connect(removeInternalViewSplitters); latteView.onXChanged.connect(visibilityManager.updateMaskArea); latteView.onYChanged.connect(visibilityManager.updateMaskArea); latteView.onWidthChanged.connect(visibilityManager.updateMaskArea); latteView.onHeightChanged.connect(visibilityManager.updateMaskArea); latteView.positioner.hideDockDuringLocationChangeStarted.connect(visibilityManager.slotHideDockDuringLocationChange); latteView.positioner.showDockAfterLocationChangeFinished.connect(visibilityManager.slotShowDockAfterLocationChange); latteView.positioner.hideDockDuringScreenChangeStarted.connect(visibilityManager.slotHideDockDuringLocationChange); latteView.positioner.showDockAfterScreenChangeFinished.connect(visibilityManager.slotShowDockAfterLocationChange); latteView.positioner.hideDockDuringMovingToLayoutStarted.connect(visibilityManager.slotHideDockDuringLocationChange); latteView.positioner.showDockAfterMovingToLayoutFinished.connect(visibilityManager.slotShowDockAfterLocationChange); latteView.visibility.onContainsMouseChanged.connect(visibilityManager.slotContainsMouseChanged); latteView.visibility.onMustBeHide.connect(visibilityManager.slotMustBeHide); latteView.visibility.onMustBeShown.connect(visibilityManager.slotMustBeShown); updateContainsOnlyPlasmaTasks(); } } onDockContainsMouseChanged: { if (!dockContainsMouse) { initializeHoveredIndexes(); } } onDragEnter: { if (plasmoid.immutable || dockIsHidden || visibilityManager.inSlidingIn || visibilityManager.inSlidingOut) { event.ignore(); return; } if (event.mimeData.formats.indexOf("application/x-orgkdeplasmataskmanager_taskbuttonitem") >= 0) { return; } if (latteApplet) { if (latteApplet.launchersDrop(event)) { root.addLaunchersMessage = true; if (root.addLaunchersInTaskManager) { return; } } else if (latteView.mimeContainsPlasmoid(event.mimeData, "audoban.applet.separator") && root.latteAppletContainer.containsPos(event)) { confirmedDragEntered = true dndSpacer.opacity = 0; dndSpacer.parent = root; return; } } if (!confirmedDragEntered) { confirmedDragEntered = true; slotAnimationsNeedLength(1); } if (!latteApplet || (latteApplet && !latteView.mimeContainsPlasmoid(event.mimeData, "org.kde.latte.plasmoid"))) { LayoutManager.insertAtCoordinates2(dndSpacer, event.x, event.y) dndSpacer.opacity = 1; } } onDragMove: { if (event.mimeData.formats.indexOf("application/x-orgkdeplasmataskmanager_taskbuttonitem") >= 0 || dockIsHidden || visibilityManager.inSlidingIn || visibilityManager.inSlidingOut) { return; } if (latteApplet) { if (latteApplet.launchersDrop(event)) { root.addLaunchersMessage = true; if (root.addLaunchersInTaskManager) { return; } } else if (latteView.mimeContainsPlasmoid(event.mimeData, "audoban.applet.separator") && root.latteAppletContainer.containsPos(event)) { confirmedDragEntered = true dndSpacer.opacity = 0; dndSpacer.parent = root; return; } } if (!latteApplet || (latteApplet && !latteView.mimeContainsPlasmoid(event.mimeData, "org.kde.latte.plasmoid"))) { LayoutManager.insertAtCoordinates2(dndSpacer, event.x, event.y) dndSpacer.opacity = 1; } } onDragLeave: { if (confirmedDragEntered) { slotAnimationsNeedLength(-1); confirmedDragEntered = false; } root.addLaunchersMessage = false; dndSpacer.opacity = 0; dndSpacer.parent = root; } onDrop: { if (dockIsHidden || visibilityManager.inSlidingIn || visibilityManager.inSlidingOut) { return; } if (event.mimeData.formats.indexOf("application/x-orgkdeplasmataskmanager_taskbuttonitem") < 0) { if (latteApplet && latteApplet.launchersDrop(event) && root.addLaunchersInTaskManager) { latteApplet.launchersDropped(event.mimeData.urls); } else if (!latteApplet || (latteApplet && !latteView.mimeContainsPlasmoid(event.mimeData, "org.kde.latte.plasmoid"))) { plasmoid.processMimeData(event.mimeData, event.x, event.y); event.accept(event.proposedAction); } } if (confirmedDragEntered) { slotAnimationsNeedLength(-1); confirmedDragEntered = false; } root.addLaunchersMessage = false; dndSpacer.opacity = 0; //! this line is very important because it positions correctly the new applets //dndSpacer.parent = root; } onMaxLengthChanged: { layoutsContainer.updateSizeForAppletsInFill(); if (root.editMode) { updateAutomaticIconSize(); } } onToolBoxChanged: { if (toolBox) { toolBox.visible = false; } } property bool automaticSizeAnimation: false; onAutomaticIconSizeBasedSizeChanged: { if (!automaticSizeAnimation) { automaticSizeAnimation = true; slotAnimationsNeedBothAxis(1); } } onIconSizeChanged: { if (((iconSize === automaticIconSizeBasedSize) || (iconSize === root.maxIconSize)) && automaticSizeAnimation){ slotAnimationsNeedBothAxis(-1); automaticSizeAnimation=false; } } onIsReadyChanged: { if (isReady && !titleTooltipDialog.visible && titleTooltipDialog.activeItemHovered){ titleTooltipDialog.show(titleTooltipDialog.activeItem, titleTooltipDialog.activeItemText); } } onIsVerticalChanged: { if (isVertical) { if (plasmoid.configuration.panelPosition === Latte.Types.Left) plasmoid.configuration.panelPosition = Latte.Types.Top; else if (plasmoid.configuration.panelPosition === Latte.Types.Right) plasmoid.configuration.panelPosition = Latte.Types.Bottom; } else { if (plasmoid.configuration.panelPosition === Latte.Types.Top) plasmoid.configuration.panelPosition = Latte.Types.Left; else if (plasmoid.configuration.panelPosition === Latte.Types.Bottom) plasmoid.configuration.panelPosition = Latte.Types.Right; } } onProportionIconSizeChanged: { if (proportionIconSize!==-1) updateAutomaticIconSize(); } // onIconSizeChanged: console.log("Icon Size Changed:"+iconSize); Component.onCompleted: { // currentLayout.isLayoutHorizontal = isHorizontal LayoutManager.plasmoid = plasmoid; LayoutManager.root = root; LayoutManager.layout = layoutsContainer.mainLayout; LayoutManager.layoutS = layoutsContainer.startLayout; LayoutManager.layoutE = layoutsContainer.endLayout; LayoutManager.lastSpacer = lastSpacer; LayoutManager.restore(); plasmoid.action("configure").visible = !plasmoid.immutable; plasmoid.action("configure").enabled = !plasmoid.immutable; inStartupTimer.start(); } Component.onDestruction: { console.debug("Destroying Latte Dock Containment ui..."); if (latteView) { latteView.onAddInternalViewSplitter.disconnect(addInternalViewSplitters); latteView.onRemoveInternalViewSplitter.disconnect(removeInternalViewSplitters); latteView.onXChanged.disconnect(visibilityManager.updateMaskArea); latteView.onYChanged.disconnect(visibilityManager.updateMaskArea); latteView.onWidthChanged.disconnect(visibilityManager.updateMaskArea); latteView.onHeightChanged.disconnect(visibilityManager.updateMaskArea); latteView.positioner.hideDockDuringLocationChangeStarted.disconnect(visibilityManager.slotHideDockDuringLocationChange); latteView.positioner.showDockAfterLocationChangeFinished.disconnect(visibilityManager.slotShowDockAfterLocationChange); latteView.positioner.hideDockDuringScreenChangeStarted.disconnect(visibilityManager.slotHideDockDuringLocationChange); latteView.positioner.showDockAfterScreenChangeFinished.disconnect(visibilityManager.slotShowDockAfterLocationChange); latteView.positioner.hideDockDuringMovingToLayoutStarted.disconnect(visibilityManager.slotHideDockDuringLocationChange); latteView.positioner.showDockAfterMovingToLayoutFinished.disconnect(visibilityManager.slotShowDockAfterLocationChange); if (latteView.visibility) { latteView.visibility.onContainsMouseChanged.disconnect(visibilityManager.slotContainsMouseChanged); latteView.visibility.onMustBeHide.disconnect(visibilityManager.slotMustBeHide); latteView.visibility.onMustBeShown.disconnect(visibilityManager.slotMustBeShown); } } } Containment.onAppletAdded: { addApplet(applet, x, y); LayoutManager.save(); updateIndexes(); } Containment.onAppletRemoved: { LayoutManager.removeApplet(applet); var flexibleFound = false; for (var i = 0; i < layoutsContainer.mainLayout.children.length; ++i) { var applet = layoutsContainer.mainLayout.children[i].applet; if (applet && ((root.isHorizontal && applet.Layout.fillWidth) || (!root.isHorizontal && applet.Layout.fillHeight)) && applet.visible) { flexibleFound = true; break } } if (!flexibleFound) { lastSpacer.parent = layoutsContainer.mainLayout; } LayoutManager.save(); updateIndexes(); updateContainsOnlyPlasmaTasks(); } Plasmoid.onUserConfiguringChanged: { if (plasmoid.immutable) { if (dragOverlay) { dragOverlay.destroy(); } return; } // console.debug("user configuring", plasmoid.userConfiguring) if (plasmoid.userConfiguring) { latteView.setBlockHiding(true); // console.log("applets------"); for (var i = 0; i < plasmoid.applets.length; ++i) { // console.log("applet:"+i); plasmoid.applets[i].expanded = false; } if (!dragOverlay) { var component = Qt.createComponent("ConfigOverlay.qml"); if (component.status == Component.Ready) { dragOverlay = component.createObject(root); } else { console.log("Could not create ConfigOverlay"); console.log(component.errorString()); } component.destroy(); } else { dragOverlay.visible = true; } } else { latteView.setBlockHiding(false); if (latteView.visibility.isHidden) { latteView.visibility.mustBeShown(); } if (dragOverlay) { dragOverlay.visible = false; dragOverlay.destroy(); } } } Plasmoid.onImmutableChanged: { plasmoid.action("configure").visible = !plasmoid.immutable; plasmoid.action("configure").enabled = !plasmoid.immutable; ///Set Preferred Sizes/// ///Notice: they are set here because if they are set with a binding ///they break the !immutable experience, the latteView becomes too small ///to add applets if (plasmoid.immutable) { if(root.isHorizontal) { root.Layout.preferredWidth = (plasmoid.configuration.panelPosition === Latte.Types.Justify ? layoutsContainer.width + 0.5*iconMargin : layoutsContainer.mainLayout.width + iconMargin); } else { root.Layout.preferredHeight = (plasmoid.configuration.panelPosition === Latte.Types.Justify ? layoutsContainer.height + 0.5*iconMargin : layoutsContainer.mainLayout.height + iconMargin); } } else { if (root.isHorizontal) { root.Layout.preferredWidth = Screen.width; } else { root.Layout.preferredHeight = Screen.height; } } visibilityManager.updateMaskArea(); } //////////////END OF CONNECTIONS //////////////START OF FUNCTIONS function addApplet(applet, x, y) { var container = appletContainerComponent.createObject(dndSpacer.parent) container.applet = applet; applet.parent = container.appletWrapper; applet.anchors.fill = container.appletWrapper; applet.visible = true; // don't show applet if it chooses to be hidden but still make it // accessible in the panelcontroller container.visible = Qt.binding(function() { return applet.status !== PlasmaCore.Types.HiddenStatus || (!plasmoid.immutable && plasmoid.userConfiguring) }) addContainerInLayout(container, applet, x, y); updateContainsOnlyPlasmaTasks(); } function addContainerInLayout(container, applet, x, y){ // Is there a DND placeholder? Replace it! if ( (dndSpacer.parent === layoutsContainer.mainLayout) || (dndSpacer.parent === layoutsContainer.startLayout) || (dndSpacer.parent===layoutsContainer.endLayout)) { LayoutManager.insertBeforeForLayout(dndSpacer.parent, dndSpacer, container); dndSpacer.parent = root; return; // If the provided position is valid, use it. } else if (x >= 0 && y >= 0) { var index = LayoutManager.insertAtCoordinates2(container, x , y); // Fall through to determining an appropriate insert position. } else { var before = null; container.animationsEnabled = false; if (lastSpacer.parent === layoutsContainer.mainLayout) { before = lastSpacer; } // Insert icons to the left of whatever is at the center (usually a Task Manager), // if it exists. // FIXME TODO: This is a real-world fix to produce a sensible initial position for // launcher icons added by launcher menu applets. The basic approach has been used // since Plasma 1. However, "add launcher to X" is a generic-enough concept and // frequent-enough occurrence that we'd like to abstract it further in the future // and get rid of the ugliness of parties external to the containment adding applets // of a specific type, and the containment caring about the applet type. In a better // system the containment would be informed of requested launchers, and determine by // itself what it wants to do with that information. if (applet.pluginName == "org.kde.plasma.icon") { var middle = layoutsContainer.mainLayout.childAt(root.width / 2, root.height / 2); if (middle) { before = middle; } // Otherwise if lastSpacer is here, enqueue before it. } if (before) { LayoutManager.insertBefore(before, container); // Fall through to adding at the end. } else { container.parent = layoutsContainer.mainLayout; } } //Important, removes the first children of the layoutsContainer.mainLayout after the first //applet has been added lastSpacer.parent = root; updateIndexes(); } function addInternalViewSplitters(){ addInternalViewSplitter(-1); addInternalViewSplitter(-1); } function addInternalViewSplitter(pos){ var splittersCount = internalViewSplittersCount(); if(splittersCount<2){ var container = appletContainerComponent.createObject(root); container.internalSplitterId = splittersCount+1; container.visible = true; if(pos>=0 ){ LayoutManager.insertAtIndex(container, pos); } else { LayoutManager.insertAtIndex(container, Math.floor(layoutsContainer.mainLayout.count / 2)); } LayoutManager.save(); } } //! it is used in order to check the right click position //! the only way to take into account the visual appearance //! of the applet (including its spacers) function appletContainsPos(appletId, pos){ for (var i = 0; i < layoutsContainer.startLayout.children.length; ++i) { var child = layoutsContainer.startLayout.children[i]; if (child && child.applet && child.applet.id === appletId && child.containsPos(pos)) return true; } for (var i = 0; i < layoutsContainer.mainLayout.children.length; ++i) { var child = layoutsContainer.mainLayout.children[i]; if (child && child.applet && child.applet.id === appletId && child.containsPos(pos)) return true; } for (var i = 0; i < layoutsContainer.endLayout.children.length; ++i) { var child = layoutsContainer.endLayout.children[i]; if (child && child.applet && child.applet.id === appletId && child.containsPos(pos)) return true; } return false; } function checkLastSpacer() { lastSpacer.parent = root var expands = false; if (isHorizontal) { for (var container in layoutsContainer.mainLayout.children) { var item = layoutsContainer.mainLayout.children[container]; if (item.Layout && item.Layout.fillWidth) { expands = true; } } } else { for (var container in layoutsContainer.mainLayout.children) { var item = layoutsContainer.mainLayout.children[container]; if (item.Layout && item.Layout.fillHeight) { expands = true; } } } if (!expands) { lastSpacer.parent = layoutsContainer.mainLayout } } function clearZoom(){ if (latteApplet){ latteApplet.clearZoom(); } root.clearZoomSignal(); } function containmentActions(){ return latteView.containmentActions(); } function decimalToHex(d, padding) { var hex = Number(d).toString(16); padding = typeof (padding) === "undefined" || padding === null ? padding = 2 : padding; while (hex.length < padding) { hex = "0" + hex; } return hex; } function disableDirectRender(){ // root.globalDirectRender = false; } function internalViewSplittersCount(){ var splitters = 0; for (var container in layoutsContainer.startLayout.children) { var item = layoutsContainer.startLayout.children[container]; if(item && item.isInternalViewSplitter) { splitters++; } } for (var container in layoutsContainer.mainLayout.children) { var item = layoutsContainer.mainLayout.children[container]; if(item && item.isInternalViewSplitter) { splitters++; } } for (var container in layoutsContainer.endLayout.children) { var item = layoutsContainer.endLayout.children[container]; if(item && item.isInternalViewSplitter) { splitters++; } } return splitters; } function initializeHoveredIndexes() { layoutsContainer.hoveredIndex = -1; layoutsContainer.currentSpot = -1000; if (latteApplet) { latteApplet.initializeHoveredIndex(); } } function layoutManagerInsertBefore(place, item) { LayoutManager.insertBefore(place, item); } function layoutManagerInsertAfter(place, item) { LayoutManager.insertAfter(place, item); } function layoutManagerSave() { LayoutManager.save(); } function layoutManagerSaveOptions() { LayoutManager.saveOptions(); } function mouseInCanBeHoveredApplet(){ if (latteApplet && latteApplet.containsMouse()) return true; var applets = layoutsContainer.startLayout.children; for(var i=0; i=0; --i){ if(iconsArray[i] === size){ return true; } } return false; } function slotAnimationsNeedBothAxis(step) { if (step === 0) { return; } animationsNeedBothAxis = Math.max(animationsNeedBothAxis + step, 0); visibilityManager.updateMaskArea(); } function slotAnimationsNeedLength(step) { if (step === 0) { return; } animationsNeedLength = Math.max(animationsNeedLength + step, 0); //when need length animations are ended it would be a good idea //to update the tasks geometries in the plasmoid if(animationsNeedLength === 0 && latteApplet) { latteApplet.publishTasksGeometries(); } visibilityManager.updateMaskArea(); } function slotAnimationsNeedThickness(step) { if (step === 0) { return; } animationsNeedThickness = Math.max(animationsNeedThickness + step, 0); visibilityManager.updateMaskArea(); } //this is used when dragging a task in order to not hide the dock //and also by the menu appearing from tasks for the same reason function slotActionsBlockHiding(step) { //if (root.editMode) { // return; // } if ((step === 0) || (!latteView)) { return; } actionsBlockHiding = Math.max(actionsBlockHiding + step, 0); if (actionsBlockHiding > 0){ latteView.setBlockHiding(true); } else { if (!root.editMode) latteView.setBlockHiding(false); } } function slotPreviewsShown(){ if (latteView) { latteView.deactivateApplets(); } } function startCheckRestoreZoomTimer(){ checkRestoreZoom.start(); } function stopCheckRestoreZoomTimer(){ checkRestoreZoom.stop(); } function startDirectRenderDelayerDuringEntering(){ directRenderDelayerForEnteringTimer.start(); } function setGlobalDirectRender(value) { if (latteApplet && latteApplet.waitingLaunchers.length > 0) return; if (value === true) { if (mouseInCanBeHoveredApplet()) { root.globalDirectRender = true; } else { // console.log("direct render true ignored..."); } } else { root.globalDirectRender = false; } } function updateAutomaticIconSize() { if ( !blockAutomaticUpdateIconSize.running && !visibilityManager.inTempHiding && ((visibilityManager.normalState || root.editMode) && (root.autoDecreaseIconSize || (!root.autoDecreaseIconSize && root.iconSize!=root.maxIconSize))) && (iconSize===root.maxIconSize || iconSize === automaticIconSizeBasedSize) ) { blockAutomaticUpdateIconSize.start(); var layoutLength; var maxLength = root.maxLength; //console.log("------Entered check-----"); //console.log("max length: "+ maxLength); if (root.isVertical) { layoutLength = (plasmoid.configuration.panelPosition === Latte.Types.Justify) ? layoutsContainer.startLayout.height+layoutsContainer.mainLayout.height+layoutsContainer.endLayout.height : layoutsContainer.mainLayout.height } else { layoutLength = (plasmoid.configuration.panelPosition === Latte.Types.Justify) ? layoutsContainer.startLayout.width+layoutsContainer.mainLayout.width+layoutsContainer.endLayout.width : layoutsContainer.mainLayout.width } var toShrinkLimit = maxLength-((root.zoomFactor-1)*(iconSize+2*iconMargin)); var toGrowLimit = maxLength-1.5*((root.zoomFactor-1)*(iconSize+2*iconMargin)); var newIconSizeFound = false; if (layoutLength > toShrinkLimit) { //must shrink // console.log("step3"); var nextIconSize = root.maxIconSize; do { nextIconSize = nextIconSize - iconStep; var factor = nextIconSize / iconSize; var nextLength = factor * layoutLength; } while ( (nextLength>toShrinkLimit) && (nextIconSize !== 16)); automaticIconSizeBasedSize = nextIconSize; newIconSizeFound = true; console.log("Step 3 - found:"+automaticIconSizeBasedSize); } else if ((layoutLength 0) { if (foundGoodSize === root.maxIconSize) { automaticIconSizeBasedSize = -1; } else { automaticIconSizeBasedSize = foundGoodSize; } newIconSizeFound = true // console.log("Step 4 - found:"+automaticIconSizeBasedSize); } else { // console.log("Step 4 - did not found..."); } } } } function updateContainsOnlyPlasmaTasks() { if (latteView) { root.containsOnlyPlasmaTasks = (latteView.tasksPresent() && !latteView.latteTasksPresent()); } else { root.containsOnlyPlasmaTasks = false; } } function updateSizeForAppletsInFill() { layoutsContainer.updateSizeForAppletsInFill(); } function updateLayouts(){ if(!root.editMode){ // console.log("update layout - internal view splitters count:"+internalViewSplittersCount()); if (internalViewSplittersCount() === 2) { var splitter = -1; var splitter2 = -1; var totalChildren = layoutsContainer.mainLayout.children.length; for (var i=0; i=0 && splitter2 === -1) { splitter2 = i; } } // console.log("update layouts 1:"+splitter + " - "+splitter2); for (var i=0; i<=splitter; ++i){ var item = layoutsContainer.mainLayout.children[0]; item.parent = layoutsContainer.startLayout; } splitter2 = splitter2 - splitter - 1; // console.log("update layouts 2:"+splitter + " - "+splitter2); totalChildren = layoutsContainer.mainLayout.children.length; for (var i=splitter2+1; i=0; --i) { var item1 = layoutsContainer.mainLayout.children[0]; item1.parent = layoutsContainer.startLayout; } var totalChildren2 = layoutsContainer.endLayout.children.length; for (var i=totalChildren2-1; i>=0; --i) { var item2 = layoutsContainer.endLayout.children[0]; item2.parent = layoutsContainer.startLayout; } var totalChildrenL = layoutsContainer.startLayout.children.length; for (var i=totalChildrenL-1; i>=0; --i) { var itemL = layoutsContainer.startLayout.children[0]; itemL.parent = layoutsContainer.mainLayout; } } } updateIndexes(); } //END functions ////BEGIN interfaces Connections { target: Latte.WindowSystem onCompositingActiveChanged: { visibilityManager.updateMaskArea(); } } Connections { target: latteView onWidthChanged:{ if (root.isHorizontal && proportionIconSize!==-1) updateAutomaticIconSize(); } onHeightChanged:{ if (root.isVertical && proportionIconSize!==-1) updateAutomaticIconSize(); } onContextMenuIsShownChanged: { if (!latteView.contextMenuIsShown) { checkRestoreZoom.start(); } else { root.setGlobalDirectRender(false); } } } Connections{ target: latteView && latteView.visibility ? latteView.visibility : root ignoreUnknownSignals : true onContainsMouseChanged: { if (mouseInHoverableArea()) { stopCheckRestoreZoomTimer(); } else { startCheckRestoreZoomTimer(); } } } Connections{ target: layoutsContainer onHoveredIndexChanged: { if (latteApplet && layoutsContainer.hoveredIndex>-1){ latteApplet.setHoveredIndex(-1); } if (latteApplet && latteApplet.windowPreviewIsShown && layoutsContainer.hoveredIndex>-1) { latteApplet.hidePreview(); } } } ////END interfaces /////BEGIN: Title Tooltip/////////// PlasmaCore.Dialog{ id: titleTooltipDialog type: PlasmaCore.Dialog.Tooltip flags: Qt.WindowStaysOnTopHint | Qt.WindowDoesNotAcceptFocus | Qt.ToolTip location: plasmoid.location mainItem: RowLayout{ Layout.fillWidth: true Layout.fillHeight: true PlasmaComponents.Label{ id:titleLbl Layout.leftMargin: 4 Layout.rightMargin: 4 Layout.topMargin: 2 Layout.bottomMargin: 2 text: titleTooltipDialog.title } } visible: false property string title: "" property bool activeItemHovered: false property Item activeItem: null property Item activeItemTooltipParent: null property string activeItemText: "" Component.onCompleted: { root.clearZoomSignal.connect(titleTooltipDialog.hide); } Component.onDestruction: { root.clearZoomSignal.disconnect(titleTooltipDialog.hide); } function hide(debug){ if (!root.titleTooltips) return; activeItemHovered = false; hideTitleTooltipTimer.start(); } function show(taskItem, text){ if (!root.titleTooltips || (latteApplet && latteApplet.contextMenu)){ return; } activeItemHovered = true; if (activeItem !== taskItem) { activeItem = taskItem; activeItemTooltipParent = taskItem.tooltipVisualParent; activeItemText = text; } if (isReady) { showTitleTooltipTimer.start(); } } function update() { activeItemHovered = true title = activeItemText; visualParent = activeItemTooltipParent; if (latteApplet && latteApplet.windowPreviewIsShown) { latteApplet.hidePreview(); } visible = true; } } Timer { id: showTitleTooltipTimer interval: 100 onTriggered: { if (latteView && latteView.visibility && latteView.visibility.containsMouse) { titleTooltipDialog.update(); } if (titleTooltipDialog.visible) { titleTooltipCheckerToNotShowTimer.start(); } if (root.debugModeTimers) { console.log("containment timer: showTitleTooltipTimer called..."); } } } Timer { id: hideTitleTooltipTimer interval: 200 onTriggered: { if (!titleTooltipDialog.activeItemHovered) { titleTooltipDialog.visible = false; } if (root.debugModeTimers) { console.log("containment timer: hideTitleTooltipTimer called..."); } } } //! Timer to fix #811, rare cases that both a window preview and context menu are //! shown Timer { id: titleTooltipCheckerToNotShowTimer interval: 250 onTriggered: { if (titleTooltipDialog.visible && latteApplet && (latteApplet.contextMenu || latteApplet.windowPreviewIsShown)) { titleTooltipDialog.visible = false; } } } /////END: Title Tooltip/////////// ///////////////BEGIN components Component { id: appletContainerComponent Applet.AppletItem{} } ParabolicManager{ id: _parabolicManager } ///////////////END components PlasmaCore.ColorScope{ id: colorScopePalette } ///////////////BEGIN UI elements //it is used to check if the mouse is outside the layoutsContainer borders, //so in that case the onLeave event behavior should be trigerred RootMouseArea{ id: rootMouseArea } Loader{ active: root.debugModeWindow sourceComponent: DebugWindow{} } //! Load a sepia background in order to avoid black background Loader{ anchors.fill: parent active: !Latte.WindowSystem.compositingActive sourceComponent: Image{ anchors.fill: parent fillMode: Image.Tile source: root.hasUserSpecifiedBackground ? latteView.managedLayout.background : "../icons/wheatprint.jpg" } } EditModeVisual{ id:editModeVisual // z: root.behaveAsPlasmaPanel ? 1 : 0 } Ruler{id: ruler} RulerMouseArea{ id: rulerMouseArea anchors.fill: ruler z:1100 } Item{ id: panelBox anchors.fill:layoutsContainer // z: root.behaveAsPlasmaPanel ? 0 : 1 PanelBox{ id: panelBoxBackground } } Item { id: lastSpacer parent: layoutsContainer.mainLayout Layout.fillWidth: true Layout.fillHeight: true z:10 Rectangle{ anchors.fill: parent color: "transparent" border.color: "yellow" border.width: 1 } } Item { id: dndSpacer property int normalSize: root.statesLineSize + root.iconSize + root.thickMargin - 1 //visibilityManager.statesLineSizeOriginal + root.maxIconSize + visibilityManager.iconMarginOriginal - 1 width: normalSize height: normalSize Layout.preferredWidth: width Layout.preferredHeight: height opacity: 0 z:10 AddWidgetVisual{} } Loader{ anchors.fill: parent active: root.debugMode z:10 sourceComponent: Item{ Rectangle{ anchors.fill: parent color: "yellow" opacity: 0.30 } } } VisibilityManager{ id: visibilityManager } LayoutsContainer { id: layoutsContainer } Colorizer.Manager { id: colorizerManager } ///////////////END UI elements ///////////////BEGIN TIMER elements //Timer to check if the mouse is still outside the latteView in order to restore zooms to 1.0 Timer{ id:checkRestoreZoom interval: 90 onTriggered: { if (latteApplet && (latteApplet.previewContainsMouse() || latteApplet.contextMenu)) return; if (latteView.contextMenuIsShown) return; if (!mouseInHoverableArea()) { setGlobalDirectRender(false); root.initializeHoveredIndexes(); root.clearZoom(); } if (root.debugModeTimers) { console.log("containment timer: checkRestoreZoom called..."); } } } //! Delayer in order to not activate directRendering when the mouse //! enters until the timer has ended. This way we make sure that the //! zoom-in animations will have ended. Timer{ id:directRenderDelayerForEnteringTimer interval: 3.2 * root.durationTime * units.shortDuration } //this is a delayer to update mask area, it is used in cases //that animations can not catch up with animations signals //e.g. the automaicIconSize case Timer{ id:delayUpdateMaskArea repeat:false; interval:300; onTriggered: { if (layoutsContainer.animationSent) { root.slotAnimationsNeedLength(-1); layoutsContainer.animationSent = false; } visibilityManager.updateMaskArea(); if (root.debugModeTimers) { console.log("containment timer: delayUpdateMaskArea called..."); } } } // This function is very costly! This timer makes sure that it can be called // only once every 1sec. Timer{ id:blockAutomaticUpdateIconSize interval: 1000 repeat: false onTriggered: root.updateAutomaticIconSize(); } //! It is used in order to slide-in the latteView on startup Timer{ id: inStartupTimer interval: 1500 repeat: false onTriggered: { if (inStartup) { visibilityManager.slotMustBeShown(); } } } ///////////////END TIMER elements }