mirror of
https://github.com/KDE/latte-dock.git
synced 2024-12-24 17:33:50 +03:00
1648 lines
47 KiB
C++
1648 lines
47 KiB
C++
/*
|
|
* Copyright 2016 Smith AR <audoban@openmailbox.org>
|
|
* Michail Vourlakos <mvourlakos@gmail.com>
|
|
*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "view.h"
|
|
|
|
// local
|
|
#include "contextmenu.h"
|
|
#include "effects.h"
|
|
#include "positioner.h"
|
|
#include "visibilitymanager.h"
|
|
#include "settings/primaryconfigview.h"
|
|
#include "settings/secondaryconfigview.h"
|
|
#include "settings/viewsettingsfactory.h"
|
|
#include "settings/widgetexplorerview.h"
|
|
#include "../apptypes.h"
|
|
#include "../lattecorona.h"
|
|
#include "../data/layoutdata.h"
|
|
#include "../declarativeimports/interfaces.h"
|
|
#include "../indicator/factory.h"
|
|
#include "../layout/genericlayout.h"
|
|
#include "../layouts/manager.h"
|
|
#include "../plasma/extended/theme.h"
|
|
#include "../screenpool.h"
|
|
#include "../settings/universalsettings.h"
|
|
#include "../settings/exporttemplatedialog/exporttemplatedialog.h"
|
|
#include "../shortcuts/globalshortcuts.h"
|
|
#include "../shortcuts/shortcutstracker.h"
|
|
|
|
// Qt
|
|
#include <QAction>
|
|
#include <QDragEnterEvent>
|
|
#include <QDragMoveEvent>
|
|
#include <QDropEvent>
|
|
#include <QMouseEvent>
|
|
#include <QQmlContext>
|
|
#include <QQmlEngine>
|
|
#include <QQmlProperty>
|
|
#include <QQuickItem>
|
|
#include <QMenu>
|
|
|
|
// KDe
|
|
#include <KActionCollection>
|
|
#include <KActivities/Consumer>
|
|
#include <KWayland/Client/plasmashell.h>
|
|
#include <KWayland/Client/surface.h>
|
|
#include <KWindowSystem>
|
|
|
|
// Plasma
|
|
#include <Plasma/Containment>
|
|
#include <Plasma/ContainmentActions>
|
|
#include <PlasmaQuick/AppletQuickItem>
|
|
|
|
#define BLOCKHIDINGDRAGTYPE "View::ContainsDrag()"
|
|
#define BLOCKHIDINGNEEDSATTENTIONTYPE "View::Containment::NeedsAttentionState()"
|
|
#define BLOCKHIDINGREQUESTSINPUTTYPE "View::Containment::RequestsInputState()"
|
|
|
|
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_interface(new ViewPart::ContainmentInterface(this)),
|
|
m_parabolic(new ViewPart::Parabolic(this)),
|
|
m_sink(new ViewPart::EventsSink(this))
|
|
{
|
|
//! needs to be created after Effects because it catches some of its signals
|
|
//! and avoid a crash from View::winId() at the same time
|
|
m_positioner = new ViewPart::Positioner(this);
|
|
|
|
// setTitle(corona->kPackage().metadata().name());
|
|
setIcon(qGuiApp->windowIcon());
|
|
setResizeMode(QuickViewSharedEngine::SizeRootObjectToView);
|
|
setColor(QColor(Qt::transparent));
|
|
setClearBeforeRendering(true);
|
|
|
|
const auto flags = Qt::FramelessWindowHint
|
|
| Qt::NoDropShadowWindowHint
|
|
| Qt::WindowDoesNotAcceptFocus;
|
|
|
|
if (byPassWM) {
|
|
setFlags(flags | Qt::BypassWindowManagerHint);
|
|
} else {
|
|
setFlags(flags);
|
|
}
|
|
|
|
if (targetScreen)
|
|
m_positioner->setScreenToFollow(targetScreen);
|
|
else
|
|
m_positioner->setScreenToFollow(qGuiApp->primaryScreen());
|
|
|
|
m_releaseGrabTimer.setInterval(400);
|
|
m_releaseGrabTimer.setSingleShot(true);
|
|
connect(&m_releaseGrabTimer, &QTimer::timeout, this, &View::releaseGrab);
|
|
|
|
connect(m_contextMenu, &ViewPart::ContextMenu::menuChanged, this, &View::updateTransientWindowsTracking);
|
|
|
|
connect(this, &View::containmentChanged
|
|
, this, [ &, byPassWM]() {
|
|
qDebug() << "dock view c++ containment changed 1...";
|
|
|
|
if (!this->containment())
|
|
return;
|
|
|
|
qDebug() << "dock view c++ containment changed 2...";
|
|
|
|
setTitle(validTitle());
|
|
|
|
//! 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);
|
|
emit windowsTrackerChanged();
|
|
}
|
|
|
|
if (!m_visibility) {
|
|
m_visibility = new ViewPart::VisibilityManager(this);
|
|
|
|
connect(m_visibility, &ViewPart::VisibilityManager::isHiddenChanged, this, [&]() {
|
|
if (m_visibility->isHidden()) {
|
|
m_interface->deactivateApplets();
|
|
}
|
|
});
|
|
|
|
connect(m_visibility, &ViewPart::VisibilityManager::containsMouseChanged,
|
|
this, &View::updateTransientWindowsTracking);
|
|
|
|
//! Deprecated because with Plasma 5.19.3 the issue does not appear.
|
|
//! The issue was that when FrameExtents where zero strange behaviors were
|
|
//! occuring from KWin, e.g. the panels were moving outside of screen and
|
|
//! panel external shadows were positioned out of place.
|
|
/*connect(m_visibility, &ViewPart::VisibilityManager::frameExtentsCleared, this, [&]() {
|
|
if (behaveAsPlasmaPanel()) {
|
|
//! recreate view because otherwise compositor frame extents implementation
|
|
//! is triggering a crazy behavior of moving/hiding the view and freezing Latte
|
|
//! in some cases.
|
|
//reloadSource();
|
|
}
|
|
});*/
|
|
|
|
emit visibilityChanged();
|
|
}
|
|
|
|
if (!m_indicator) {
|
|
m_indicator = new ViewPart::Indicator(this);
|
|
emit indicatorChanged();
|
|
}
|
|
|
|
if (m_positioner) {
|
|
//! immediateSyncGeometry helps avoiding binding loops from containment qml side
|
|
m_positioner->immediateSyncGeometry();
|
|
}
|
|
|
|
connect(this->containment(), SIGNAL(statusChanged(Plasma::Types::ItemStatus)), SLOT(statusChanged(Plasma::Types::ItemStatus)));
|
|
connect(this->containment(), &Plasma::Containment::showAddWidgetsInterface, this, &View::showWidgetExplorer);
|
|
connect(this->containment(), &Plasma::Containment::userConfiguringChanged, this, [&]() {
|
|
emit inEditModeChanged();
|
|
});
|
|
|
|
if (m_corona->viewSettingsFactory()->hasOrphanSettings()
|
|
&& m_corona->viewSettingsFactory()->hasVisibleSettings()
|
|
&& m_corona->viewSettingsFactory()->lastContainment() == containment()) {
|
|
//! used mostly from view recreations in order to inform config windows that view has been updated
|
|
m_primaryConfigView = m_corona->viewSettingsFactory()->primaryConfigView();
|
|
m_primaryConfigView->setParentView(this, true);
|
|
}
|
|
|
|
emit containmentActionsChanged();
|
|
}, Qt::DirectConnection);
|
|
|
|
m_corona = qobject_cast<Latte::Corona *>(this->corona());
|
|
|
|
if (m_corona) {
|
|
connect(m_corona, &Latte::Corona::viewLocationChanged, this, &View::dockLocationChanged);
|
|
}
|
|
}
|
|
|
|
View::~View()
|
|
{
|
|
m_inDelete = true;
|
|
|
|
//! clear Layout connections
|
|
m_visibleHackTimer1.stop();
|
|
m_visibleHackTimer2.stop();
|
|
for (auto &c : connectionsLayout) {
|
|
disconnect(c);
|
|
}
|
|
|
|
//! unload indicators
|
|
if (m_indicator) {
|
|
m_indicator->unloadIndicators();
|
|
}
|
|
|
|
disconnectSensitiveSignals();
|
|
disconnect(containment(), SIGNAL(statusChanged(Plasma::Types::ItemStatus)), this, SLOT(statusChanged(Plasma::Types::ItemStatus)));
|
|
|
|
qDebug() << "dock view deleting...";
|
|
|
|
//! 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_primaryConfigView && m_corona->inQuit()) {
|
|
//! delete only when application is quitting
|
|
delete m_primaryConfigView;
|
|
}
|
|
|
|
if (m_appletConfigView) {
|
|
delete m_appletConfigView;
|
|
}
|
|
|
|
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_indicator) {
|
|
delete m_indicator;
|
|
}
|
|
|
|
if (m_interface) {
|
|
delete m_interface;
|
|
}
|
|
|
|
if (m_visibility) {
|
|
delete m_visibility;
|
|
}
|
|
|
|
if (m_windowsTracker) {
|
|
delete m_windowsTracker;
|
|
}
|
|
}
|
|
|
|
void View::init(Plasma::Containment *plasma_containment)
|
|
{
|
|
connect(this, &QQuickWindow::xChanged, this, &View::geometryChanged);
|
|
connect(this, &QQuickWindow::yChanged, this, &View::geometryChanged);
|
|
connect(this, &QQuickWindow::widthChanged, this, &View::geometryChanged);
|
|
connect(this, &QQuickWindow::heightChanged, this, &View::geometryChanged);
|
|
|
|
connect(this, &QQuickWindow::xChanged, this, &View::xChanged);
|
|
connect(this, &QQuickWindow::xChanged, this, &View::updateAbsoluteGeometry);
|
|
connect(this, &QQuickWindow::yChanged, this, &View::yChanged);
|
|
connect(this, &QQuickWindow::yChanged, this, &View::updateAbsoluteGeometry);
|
|
connect(this, &QQuickWindow::widthChanged, this, &View::widthChanged);
|
|
connect(this, &QQuickWindow::widthChanged, this, &View::updateAbsoluteGeometry);
|
|
connect(this, &QQuickWindow::heightChanged, this, &View::heightChanged);
|
|
connect(this, &QQuickWindow::heightChanged, this, &View::updateAbsoluteGeometry);
|
|
|
|
connect(this, &View::fontPixelSizeChanged, this, &View::editThicknessChanged);
|
|
connect(this, &View::maxNormalThicknessChanged, this, &View::editThicknessChanged);
|
|
|
|
connect(this, &View::activitiesChanged, this, &View::applyActivitiesToWindows);
|
|
|
|
connect(this, &View::localGeometryChanged, this, [&]() {
|
|
updateAbsoluteGeometry();
|
|
});
|
|
connect(this, &View::screenEdgeMarginEnabledChanged, this, [&]() {
|
|
updateAbsoluteGeometry();
|
|
});
|
|
|
|
//! used in order to disconnect it when it should NOT be called because it creates crashes
|
|
connect(this, &View::availableScreenRectChangedFrom, m_corona, &Latte::Corona::availableScreenRectChangedFrom);
|
|
connect(this, &View::availableScreenRegionChangedFrom, m_corona, &Latte::Corona::availableScreenRegionChangedFrom);
|
|
connect(m_corona, &Latte::Corona::availableScreenRectChangedFrom, this, &View::availableScreenRectChangedFromSlot);
|
|
connect(m_corona, &Latte::Corona::verticalUnityViewHasFocus, this, &View::topViewAlwaysOnTop);
|
|
|
|
connect(this, &View::byPassWMChanged, this, &View::saveConfig);
|
|
connect(this, &View::isPreferredForShortcutsChanged, this, &View::saveConfig);
|
|
connect(this, &View::onPrimaryChanged, this, &View::saveConfig);
|
|
connect(this, &View::typeChanged, this, &View::saveConfig);
|
|
|
|
connect(this, &View::normalThicknessChanged, this, [&]() {
|
|
emit availableScreenRectChangedFrom(this);
|
|
});
|
|
|
|
connect(m_effects, &ViewPart::Effects::innerShadowChanged, this, [&]() {
|
|
emit availableScreenRectChangedFrom(this);
|
|
});
|
|
connect(m_positioner, &ViewPart::Positioner::onHideWindowsForSlidingOut, this, &View::hideWindowsForSlidingOut);
|
|
connect(m_positioner, &ViewPart::Positioner::screenGeometryChanged, this, &View::screenGeometryChanged);
|
|
connect(m_positioner, &ViewPart::Positioner::windowSizeChanged, this, [&]() {
|
|
emit availableScreenRectChangedFrom(this);
|
|
});
|
|
|
|
connect(m_contextMenu, &ViewPart::ContextMenu::menuChanged, this, &View::contextMenuIsShownChanged);
|
|
|
|
connect(m_interface, &ViewPart::ContainmentInterface::hasExpandedAppletChanged, this, &View::verticalUnityViewHasFocus);
|
|
|
|
//! View sends this signal in order to avoid crashes from ViewPart::Indicator when the view is recreated
|
|
connect(m_corona->indicatorFactory(), &Latte::Indicator::Factory::indicatorChanged, this, [&](const QString &indicatorId) {
|
|
emit indicatorPluginChanged(indicatorId);
|
|
});
|
|
|
|
connect(this, &View::indicatorPluginChanged, this, [&](const QString &indicatorId) {
|
|
if (m_indicator && m_indicator->isCustomIndicator() && m_indicator->type() == indicatorId) {
|
|
reloadSource();
|
|
}
|
|
});
|
|
|
|
connect(m_corona->indicatorFactory(), &Latte::Indicator::Factory::indicatorRemoved, this, &View::indicatorPluginRemoved);
|
|
|
|
//! Assign app interfaces in be accessible through containment graphic item
|
|
QQuickItem *containmentGraphicItem = qobject_cast<QQuickItem *>(plasma_containment->property("_plasma_graphicObject").value<QObject *>());
|
|
|
|
if (containmentGraphicItem) {
|
|
containmentGraphicItem->setProperty("_latte_globalShortcuts_object", QVariant::fromValue(m_corona->globalShortcuts()->shortcutsTracker()));
|
|
containmentGraphicItem->setProperty("_latte_layoutsManager_object", QVariant::fromValue(m_corona->layoutsManager()));
|
|
containmentGraphicItem->setProperty("_latte_themeExtended_object", QVariant::fromValue(m_corona->themeExtended()));
|
|
containmentGraphicItem->setProperty("_latte_universalSettings_object", QVariant::fromValue(m_corona->universalSettings()));
|
|
containmentGraphicItem->setProperty("_latte_view_object", QVariant::fromValue(this));
|
|
|
|
Latte::Interfaces *ifacesGraphicObject = qobject_cast<Latte::Interfaces *>(containmentGraphicItem->property("_latte_view_interfacesobject").value<QObject *>());
|
|
|
|
if (ifacesGraphicObject) {
|
|
ifacesGraphicObject->updateView();
|
|
setInterfacesGraphicObj(ifacesGraphicObject);
|
|
}
|
|
}
|
|
|
|
setSource(corona()->kPackage().filePath("lattedockui"));
|
|
|
|
//! immediateSyncGeometry helps avoiding binding loops from containment qml side
|
|
m_positioner->immediateSyncGeometry();
|
|
|
|
qDebug() << "SOURCE:" << source();
|
|
}
|
|
|
|
void View::reloadSource()
|
|
{
|
|
if (m_layout && containment()) {
|
|
// if (settingsWindowIsShown()) {
|
|
// m_configView->deleteLater();
|
|
// }
|
|
|
|
engine()->clearComponentCache();
|
|
m_layout->recreateView(containment(), settingsWindowIsShown());
|
|
}
|
|
}
|
|
|
|
bool View::inDelete() const
|
|
{
|
|
return m_inDelete;
|
|
}
|
|
|
|
bool View::inReadyState() const
|
|
{
|
|
return (m_layout != nullptr);
|
|
}
|
|
|
|
void View::disconnectSensitiveSignals()
|
|
{
|
|
m_initLayoutTimer.stop();
|
|
|
|
disconnect(this, &View::availableScreenRectChangedFrom, m_corona, &Latte::Corona::availableScreenRectChangedFrom);
|
|
disconnect(this, &View::availableScreenRegionChangedFrom, m_corona, &Latte::Corona::availableScreenRegionChangedFrom);
|
|
disconnect(m_corona, &Latte::Corona::availableScreenRectChangedFrom, this, &View::availableScreenRectChangedFromSlot);
|
|
disconnect(m_corona, &Latte::Corona::verticalUnityViewHasFocus, this, &View::topViewAlwaysOnTop);
|
|
|
|
setLayout(nullptr);
|
|
}
|
|
|
|
void View::availableScreenRectChangedFromSlot(View *origin)
|
|
{
|
|
if (m_inDelete || origin == this || !origin) {
|
|
return;
|
|
}
|
|
|
|
if (formFactor() == Plasma::Types::Vertical
|
|
&& origin->layout()
|
|
&& m_layout
|
|
&& origin->layout()->lastUsedActivity() == m_layout->lastUsedActivity()) {
|
|
//! must be in same activity
|
|
m_positioner->syncGeometry();
|
|
}
|
|
}
|
|
|
|
void View::setupWaylandIntegration()
|
|
{
|
|
if (m_shellSurface)
|
|
return;
|
|
|
|
if (Latte::Corona *c = qobject_cast<Latte::Corona *>(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...";
|
|
if (m_visibility) {
|
|
m_visibility->initViewFlags();
|
|
}
|
|
if (m_positioner) {
|
|
m_positioner->updateWaylandId();
|
|
}
|
|
}
|
|
}
|
|
|
|
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::duplicateView()
|
|
{
|
|
m_layout->duplicateView(containment());
|
|
}
|
|
|
|
void View::exportTemplate()
|
|
{
|
|
Latte::Settings::Dialog::ExportTemplateDialog *exportDlg = new Latte::Settings::Dialog::ExportTemplateDialog(this);
|
|
exportDlg->show();
|
|
}
|
|
|
|
void View::removeView()
|
|
{
|
|
if (m_layout) {
|
|
m_inDelete = true;
|
|
|
|
QAction *removeAct = action("remove");
|
|
|
|
if (removeAct) {
|
|
removeAct->trigger();
|
|
}
|
|
}
|
|
}
|
|
|
|
bool View::settingsWindowIsShown()
|
|
{
|
|
return m_primaryConfigView && (m_primaryConfigView->parentView()==this) && m_primaryConfigView->isVisible();
|
|
}
|
|
|
|
void View::showSettingsWindow()
|
|
{
|
|
if (!settingsWindowIsShown()) {
|
|
emit m_visibility->mustBeShown();
|
|
showConfigurationInterface(containment());
|
|
applyActivitiesToWindows();
|
|
}
|
|
}
|
|
|
|
QQuickView *View::configView()
|
|
{
|
|
return m_primaryConfigView.data();
|
|
}
|
|
|
|
void View::showConfigurationInterface(Plasma::Applet *applet)
|
|
{
|
|
if (!applet || !applet->containment())
|
|
return;
|
|
|
|
Plasma::Containment *c = qobject_cast<Plasma::Containment *>(applet);
|
|
|
|
if (m_primaryConfigView && c && c->isContainment() && c == this->containment()) {
|
|
if (m_primaryConfigView->isVisible()) {
|
|
m_primaryConfigView->hideConfigWindow();
|
|
} else {
|
|
m_primaryConfigView->showConfigWindow();
|
|
applyActivitiesToWindows();
|
|
}
|
|
|
|
return;
|
|
} else if (m_appletConfigView) {
|
|
if (m_appletConfigView->applet() == applet) {
|
|
m_appletConfigView->show();
|
|
|
|
if (KWindowSystem::isPlatformX11()) {
|
|
m_appletConfigView->requestActivate();
|
|
}
|
|
return;
|
|
} else {
|
|
m_appletConfigView->hide();
|
|
}
|
|
}
|
|
|
|
bool delayConfigView = false;
|
|
|
|
if (c && containment() && c->isContainment() && c->id() == containment()->id()) {
|
|
m_primaryConfigView = m_corona->viewSettingsFactory()->primaryConfigView(this);
|
|
applyActivitiesToWindows();
|
|
} else {
|
|
m_appletConfigView = new PlasmaQuick::ConfigView(applet);
|
|
m_appletConfigView.data()->init();
|
|
m_appletConfigView->show();
|
|
}
|
|
}
|
|
|
|
void View::showWidgetExplorer(const QPointF &point)
|
|
{
|
|
auto widgetExplorerView = m_corona->viewSettingsFactory()->widgetExplorerView(this);
|
|
|
|
if (!widgetExplorerView->isVisible()) {
|
|
widgetExplorerView->showAfter(250);
|
|
}
|
|
}
|
|
|
|
QRect View::localGeometry() const
|
|
{
|
|
return m_localGeometry;
|
|
}
|
|
|
|
void View::setLocalGeometry(const QRect &geometry)
|
|
{
|
|
if (m_localGeometry == geometry) {
|
|
return;
|
|
}
|
|
|
|
m_localGeometry = geometry;
|
|
emit localGeometryChanged();
|
|
}
|
|
|
|
QString View::validTitle() const
|
|
{
|
|
if (!containment()) {
|
|
return QString();
|
|
}
|
|
|
|
return QString("#view#" + QString::number(containment()->id()));
|
|
}
|
|
|
|
void View::updateAbsoluteGeometry(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 = m_localGeometry;
|
|
absGeometry.moveLeft(x() + m_localGeometry.x());
|
|
absGeometry.moveTop(y() + m_localGeometry.y());
|
|
|
|
if (behaveAsPlasmaPanel()) {
|
|
int currentScreenEdgeMargin = m_screenEdgeMarginEnabled ? qMax(0, m_screenEdgeMargin) : 0;
|
|
|
|
if (location() == Plasma::Types::BottomEdge) {
|
|
absGeometry.moveTop(screenGeometry().bottom() - currentScreenEdgeMargin - m_normalThickness);
|
|
} else if (location() == Plasma::Types::TopEdge) {
|
|
absGeometry.moveTop(screenGeometry().top() + currentScreenEdgeMargin);
|
|
} else if (location() == Plasma::Types::LeftEdge) {
|
|
absGeometry.moveLeft(screenGeometry().left() + currentScreenEdgeMargin);
|
|
} else if (location() == Plasma::Types::RightEdge) {
|
|
absGeometry.moveLeft(screenGeometry().right() - currentScreenEdgeMargin - m_normalThickness);
|
|
}
|
|
}
|
|
|
|
if (m_absoluteGeometry == absGeometry && !bypassChecks) {
|
|
return;
|
|
}
|
|
|
|
if (m_absoluteGeometry != absGeometry) {
|
|
m_absoluteGeometry = absGeometry;
|
|
emit absoluteGeometryChanged(m_absoluteGeometry);
|
|
}
|
|
|
|
//! this is needed in order to update correctly the screenGeometries
|
|
if (visibility() && corona() && visibility()->mode() == Types::AlwaysVisible) {
|
|
//! main use of BYPASSCKECKS is from Positioner when the view changes screens
|
|
emit availableScreenRectChangedFrom(this);
|
|
emit availableScreenRegionChangedFrom(this);
|
|
}
|
|
}
|
|
|
|
void View::statusChanged(Plasma::Types::ItemStatus status)
|
|
{
|
|
if (!containment()) {
|
|
return;
|
|
}
|
|
|
|
if (status == Plasma::Types::NeedsAttentionStatus) {
|
|
m_visibility->addBlockHidingEvent(BLOCKHIDINGNEEDSATTENTIONTYPE);
|
|
m_visibility->initViewFlags();
|
|
} else if (status == Plasma::Types::AcceptingInputStatus) {
|
|
m_visibility->removeBlockHidingEvent(BLOCKHIDINGNEEDSATTENTIONTYPE);
|
|
setFlags(flags() & ~Qt::WindowDoesNotAcceptFocus);
|
|
KWindowSystem::forceActiveWindow(winId());
|
|
} else {
|
|
updateTransientWindowsTracking();
|
|
m_visibility->removeBlockHidingEvent(BLOCKHIDINGNEEDSATTENTIONTYPE);
|
|
m_visibility->initViewFlags();
|
|
}
|
|
}
|
|
|
|
void View::addTransientWindow(QWindow *window)
|
|
{
|
|
if (!m_transientWindows.contains(window) && !window->flags().testFlag(Qt::ToolTip) && !window->title().startsWith("#debugwindow#")) {
|
|
m_transientWindows.append(window);
|
|
|
|
QString winPtrStr = "0x" + QString::number((qulonglong)window,16);
|
|
m_visibility->addBlockHidingEvent(winPtrStr);
|
|
connect(window, &QWindow::visibleChanged, this, &View::removeTransientWindow);
|
|
}
|
|
}
|
|
|
|
void View::removeTransientWindow(const bool &visible)
|
|
{
|
|
QWindow *window = static_cast<QWindow *>(QObject::sender());
|
|
|
|
if (window && !visible) {
|
|
QString winPtrStr = "0x" + QString::number((qulonglong)window,16);
|
|
m_visibility->removeBlockHidingEvent(winPtrStr);
|
|
disconnect(window, &QWindow::visibleChanged, this, &View::removeTransientWindow);
|
|
m_transientWindows.removeAll(window);
|
|
|
|
updateTransientWindowsTracking();
|
|
}
|
|
}
|
|
|
|
void View::updateTransientWindowsTracking()
|
|
{
|
|
for(QWindow *window: qApp->topLevelWindows()) {
|
|
if (window->transientParent() == this){
|
|
if (window->isVisible()) {
|
|
addTransientWindow(window);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Types::ViewType View::type() const
|
|
{
|
|
return m_type;
|
|
}
|
|
|
|
void View::setType(Types::ViewType type)
|
|
{
|
|
if (m_type == type) {
|
|
return;
|
|
}
|
|
|
|
m_type = type;
|
|
emit typeChanged();
|
|
}
|
|
|
|
bool View::alternativesIsShown() const
|
|
{
|
|
return m_alternativesIsShown;
|
|
}
|
|
|
|
void View::setAlternativesIsShown(bool show)
|
|
{
|
|
if (m_alternativesIsShown == show) {
|
|
return;
|
|
}
|
|
|
|
m_alternativesIsShown = show;
|
|
|
|
emit alternativesIsShownChanged();
|
|
}
|
|
|
|
bool View::containsDrag() const
|
|
{
|
|
return m_containsDrag;
|
|
}
|
|
|
|
void View::setContainsDrag(bool contains)
|
|
{
|
|
if (m_containsDrag == contains) {
|
|
return;
|
|
}
|
|
|
|
m_containsDrag = contains;
|
|
|
|
|
|
if (m_containsDrag) {
|
|
m_visibility->addBlockHidingEvent(BLOCKHIDINGDRAGTYPE);
|
|
} else {
|
|
m_visibility->removeBlockHidingEvent(BLOCKHIDINGDRAGTYPE);
|
|
}
|
|
|
|
emit containsDragChanged();
|
|
}
|
|
|
|
bool View::containsMouse() const
|
|
{
|
|
return m_containsMouse;
|
|
}
|
|
|
|
bool View::contextMenuIsShown() const
|
|
{
|
|
if (!m_contextMenu) {
|
|
return false;
|
|
}
|
|
|
|
return m_contextMenu->menu();
|
|
}
|
|
|
|
int View::normalThickness() const
|
|
{
|
|
return m_normalThickness;
|
|
}
|
|
|
|
void View::setNormalThickness(int thickness)
|
|
{
|
|
if (m_normalThickness == thickness) {
|
|
return;
|
|
}
|
|
|
|
m_normalThickness = thickness;
|
|
emit normalThicknessChanged();
|
|
}
|
|
|
|
int View::maxNormalThickness() const
|
|
{
|
|
return m_maxNormalThickness;
|
|
}
|
|
|
|
void View::setMaxNormalThickness(int thickness)
|
|
{
|
|
if (m_maxNormalThickness == thickness) {
|
|
return;
|
|
}
|
|
|
|
m_maxNormalThickness = thickness;
|
|
emit maxNormalThicknessChanged();
|
|
}
|
|
|
|
int View::headThicknessGap() const
|
|
{
|
|
return m_headThicknessGap;
|
|
}
|
|
|
|
void View::setHeadThicknessGap(int thickness)
|
|
{
|
|
if (m_headThicknessGap == thickness) {
|
|
return;
|
|
}
|
|
|
|
m_headThicknessGap = thickness;
|
|
emit headThicknessGapChanged();
|
|
}
|
|
|
|
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 containment() && containment()->isUserConfiguring();
|
|
}
|
|
|
|
bool View::isFloatingPanel() const
|
|
{
|
|
return m_behaveAsPlasmaPanel && m_screenEdgeMarginEnabled && (m_screenEdgeMargin>0);
|
|
}
|
|
|
|
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_layout) {
|
|
emit m_layout->preferredViewForShortcutsChanged(this);
|
|
}
|
|
}
|
|
|
|
bool View::inSettingsAdvancedMode() const
|
|
{
|
|
return m_primaryConfigView && m_corona->universalSettings()->inAdvancedModeForEditSettings();
|
|
}
|
|
|
|
bool View::isTouchingBottomViewAndIsBusy() const
|
|
{
|
|
return m_isTouchingBottomViewAndIsBusy;
|
|
}
|
|
|
|
void View::setIsTouchingBottomViewAndIsBusy(bool touchAndBusy)
|
|
{
|
|
if (m_isTouchingBottomViewAndIsBusy == touchAndBusy) {
|
|
return;
|
|
}
|
|
|
|
m_isTouchingBottomViewAndIsBusy = touchAndBusy;
|
|
|
|
emit isTouchingBottomViewAndIsBusyChanged();
|
|
}
|
|
|
|
bool View::isTouchingTopViewAndIsBusy() const
|
|
{
|
|
return m_isTouchingTopViewAndIsBusy;
|
|
}
|
|
|
|
void View::setIsTouchingTopViewAndIsBusy(bool touchAndBusy)
|
|
{
|
|
if (m_isTouchingTopViewAndIsBusy == touchAndBusy) {
|
|
return;
|
|
}
|
|
|
|
m_isTouchingTopViewAndIsBusy = touchAndBusy;
|
|
emit isTouchingTopViewAndIsBusyChanged();
|
|
}
|
|
|
|
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::editThickness() const
|
|
{
|
|
int smallspacing = 4;
|
|
int ruler_height{m_fontPixelSize};
|
|
int header_height{m_fontPixelSize + 2*smallspacing};
|
|
|
|
int edgeThickness = behaveAsPlasmaPanel() && screenEdgeMarginEnabled() ? m_screenEdgeMargin : 0;
|
|
|
|
return edgeThickness + m_maxNormalThickness + ruler_height + header_height + 6*smallspacing;
|
|
}
|
|
|
|
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<Types::Alignment>(alignment);
|
|
|
|
if (m_alignment == alignment) {
|
|
return;
|
|
}
|
|
|
|
m_alignment = align;
|
|
emit alignmentChanged();
|
|
}
|
|
|
|
QRect View::absoluteGeometry() const
|
|
{
|
|
return m_absoluteGeometry;
|
|
}
|
|
|
|
QRect View::screenGeometry() const
|
|
{
|
|
if (this->screen()) {
|
|
QRect geom = this->screen()->geometry();
|
|
return geom;
|
|
}
|
|
|
|
return QRect();
|
|
}
|
|
|
|
float View::offset() const
|
|
{
|
|
return m_offset;
|
|
}
|
|
|
|
void View::setOffset(float offset)
|
|
{
|
|
if (m_offset == offset) {
|
|
return;
|
|
}
|
|
|
|
m_offset = offset;
|
|
emit offsetChanged();
|
|
}
|
|
|
|
bool View::screenEdgeMarginEnabled() const
|
|
{
|
|
return m_screenEdgeMarginEnabled;
|
|
}
|
|
|
|
void View::setScreenEdgeMarginEnabled(bool enabled)
|
|
{
|
|
if (m_screenEdgeMarginEnabled == enabled) {
|
|
return;
|
|
}
|
|
|
|
m_screenEdgeMarginEnabled = enabled;
|
|
emit screenEdgeMarginEnabledChanged();
|
|
}
|
|
|
|
int View::screenEdgeMargin() const
|
|
{
|
|
return m_screenEdgeMargin;
|
|
}
|
|
|
|
void View::setScreenEdgeMargin(int margin)
|
|
{
|
|
if (m_screenEdgeMargin == margin) {
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
m_screenEdgeMargin = margin;
|
|
emit screenEdgeMarginChanged();
|
|
}
|
|
|
|
int View::fontPixelSize() const
|
|
{
|
|
return m_fontPixelSize;
|
|
}
|
|
|
|
void View::setFontPixelSize(int size)
|
|
{
|
|
if (m_fontPixelSize == size) {
|
|
return;
|
|
}
|
|
|
|
m_fontPixelSize = size;
|
|
|
|
emit fontPixelSizeChanged();
|
|
}
|
|
|
|
bool View::isOnAllActivities() const
|
|
{
|
|
return m_activities.isEmpty() || m_activities[0] == Data::Layout::ALLACTIVITIESID;
|
|
}
|
|
|
|
bool View::isOnActivity(const QString &activity) const
|
|
{
|
|
return isOnAllActivities() || m_activities.contains(activity);
|
|
}
|
|
|
|
QStringList View::activities() const
|
|
{
|
|
QStringList running;
|
|
|
|
QStringList runningAll = m_corona->activitiesConsumer()->runningActivities();
|
|
|
|
for(int i=0; i<m_activities.count(); ++i) {
|
|
if (runningAll.contains(m_activities[i])) {
|
|
running << m_activities[i];
|
|
}
|
|
}
|
|
|
|
return running;
|
|
}
|
|
|
|
void View::setActivities(const QStringList &ids)
|
|
{
|
|
if (m_activities == ids) {
|
|
return;
|
|
}
|
|
|
|
m_activities = ids;
|
|
emit activitiesChanged();
|
|
}
|
|
|
|
void View::applyActivitiesToWindows()
|
|
{
|
|
if (m_visibility && m_layout) {
|
|
QStringList runningActivities = activities();
|
|
|
|
m_windowsTracker->setWindowOnActivities(*this, runningActivities);
|
|
|
|
//! config windows
|
|
if (m_primaryConfigView) {
|
|
m_primaryConfigView->setOnActivities(runningActivities);
|
|
}
|
|
|
|
if (m_appletConfigView) {
|
|
m_windowsTracker->setWindowOnActivities(*m_appletConfigView, runningActivities);
|
|
}
|
|
|
|
//! hidden windows
|
|
if (m_visibility->supportsKWinEdges()) {
|
|
m_visibility->applyActivitiesToHiddenWindows(runningActivities);
|
|
}
|
|
}
|
|
}
|
|
|
|
void View::showHiddenViewFromActivityStopping()
|
|
{
|
|
if (m_layout && m_visibility && !inDelete() && !isVisible() && !m_visibility->isHidden()) {
|
|
show();
|
|
|
|
if (m_effects) {
|
|
m_effects->updateEnabledBorders();
|
|
}
|
|
|
|
//qDebug() << "View:: Enforce reshow from timer 1...";
|
|
emit forcedShown();
|
|
} else if (m_layout && isVisible()) {
|
|
m_inDelete = false;
|
|
//qDebug() << "View:: No needed reshow from timer 1...";
|
|
}
|
|
}
|
|
|
|
Layout::GenericLayout *View::layout() const
|
|
{
|
|
return m_layout;
|
|
}
|
|
|
|
void View::setLayout(Layout::GenericLayout *layout)
|
|
{
|
|
if (m_layout == layout) {
|
|
return;
|
|
}
|
|
|
|
// clear mode
|
|
for (auto &c : connectionsLayout) {
|
|
disconnect(c);
|
|
}
|
|
|
|
m_layout = layout;
|
|
|
|
if (m_layout) {
|
|
connectionsLayout << connect(containment(), &Plasma::Applet::destroyedChanged, m_layout, &Layout::GenericLayout::destroyedChanged);
|
|
connectionsLayout << connect(containment(), &Plasma::Applet::locationChanged, m_corona, &Latte::Corona::viewLocationChanged);
|
|
connectionsLayout << connect(containment(), &Plasma::Containment::appletAlternativesRequested, m_corona, &Latte::Corona::showAlternativesForApplet, Qt::QueuedConnection);
|
|
|
|
if (m_corona->layoutsManager()->memoryUsage() == MemoryUsage::MultipleLayouts) {
|
|
connectionsLayout << connect(containment(), &Plasma::Containment::appletCreated, m_layout, &Layout::GenericLayout::appletCreated);
|
|
}
|
|
|
|
connectionsLayout << connect(m_positioner, &Latte::ViewPart::Positioner::edgeChanged, m_layout, &Layout::GenericLayout::viewEdgeChanged);
|
|
|
|
//! Sometimes the activity isnt completely ready, by adding a delay
|
|
//! we try to catch up
|
|
m_initLayoutTimer.setInterval(100);
|
|
m_initLayoutTimer.setSingleShot(true);
|
|
connectionsLayout << connect(&m_initLayoutTimer, &QTimer::timeout, this, [&]() {
|
|
if (m_layout && m_visibility) {
|
|
setActivities(m_layout->appliedActivities());
|
|
qDebug() << "DOCK VIEW FROM LAYOUT ::: " << m_layout->name() << " - activities: " << m_activities;
|
|
}
|
|
});
|
|
m_initLayoutTimer.start();
|
|
|
|
connectionsLayout << connect(m_layout, &Layout::GenericLayout::preferredViewForShortcutsChanged, this, &View::preferredViewForShortcutsChangedSlot);
|
|
|
|
Latte::Corona *latteCorona = qobject_cast<Latte::Corona *>(this->corona());
|
|
|
|
connectionsLayout << connect(latteCorona->activitiesConsumer(), &KActivities::Consumer::currentActivityChanged, this, [&]() {
|
|
if (m_layout && m_visibility) {
|
|
setActivities(m_layout->appliedActivities());
|
|
//! update activities in case KWin did its magic and assigned windows to faulty activities
|
|
applyActivitiesToWindows();
|
|
showHiddenViewFromActivityStopping();
|
|
qDebug() << "DOCK VIEW FROM LAYOUT (currentActivityChanged) ::: " << m_layout->name() << " - activities: " << m_activities;
|
|
}
|
|
});
|
|
|
|
if (latteCorona->layoutsManager()->memoryUsage() == MemoryUsage::MultipleLayouts) {
|
|
connectionsLayout << connect(latteCorona->activitiesConsumer(), &KActivities::Consumer::runningActivitiesChanged, this, [&]() {
|
|
if (m_layout && m_visibility) {
|
|
setActivities(m_layout->appliedActivities());
|
|
qDebug() << "DOCK VIEW FROM LAYOUT (runningActivitiesChanged) ::: " << m_layout->name()
|
|
<< " - activities: " << m_activities;
|
|
}
|
|
});
|
|
|
|
connectionsLayout << connect(m_layout, &Layout::GenericLayout::activitiesChanged, this, [&]() {
|
|
if (m_layout) {
|
|
setActivities(m_layout->appliedActivities());
|
|
}
|
|
});
|
|
|
|
connectionsLayout << connect(latteCorona->layoutsManager()->synchronizer(), &Layouts::Synchronizer::layoutsChanged, this, [&]() {
|
|
if (m_layout) {
|
|
setActivities(m_layout->appliedActivities());
|
|
}
|
|
});
|
|
|
|
//! BEGIN OF KWIN HACK
|
|
//! IMPORTANT ::: Fixing KWin Faulty Behavior that KWin hides ALL Views when an Activity stops
|
|
//! with no reason!!
|
|
|
|
m_visibleHackTimer1.setInterval(400);
|
|
m_visibleHackTimer2.setInterval(2500);
|
|
m_visibleHackTimer1.setSingleShot(true);
|
|
m_visibleHackTimer2.setSingleShot(true);
|
|
|
|
connectionsLayout << connect(this, &QWindow::visibleChanged, this, [&]() {
|
|
if (m_layout && !inDelete() && !isVisible() && !m_positioner->inLayoutUnloading()) {
|
|
m_visibleHackTimer1.start();
|
|
m_visibleHackTimer2.start();
|
|
}
|
|
});
|
|
|
|
connectionsLayout << connect(&m_visibleHackTimer1, &QTimer::timeout, this, [&]() {
|
|
applyActivitiesToWindows();
|
|
showHiddenViewFromActivityStopping();
|
|
emit activitiesChanged();
|
|
});
|
|
|
|
connectionsLayout << connect(&m_visibleHackTimer2, &QTimer::timeout, this, [&]() {
|
|
applyActivitiesToWindows();
|
|
showHiddenViewFromActivityStopping();
|
|
emit activitiesChanged();
|
|
});
|
|
|
|
//! END OF KWIN HACK
|
|
}
|
|
|
|
emit layoutChanged();
|
|
} else {
|
|
m_activities.clear();
|
|
}
|
|
}
|
|
|
|
void View::moveToLayout(QString layoutName)
|
|
{
|
|
if (!m_layout) {
|
|
return;
|
|
}
|
|
|
|
QList<Plasma::Containment *> containments = m_layout->unassignFromLayout(this);
|
|
|
|
Latte::Corona *latteCorona = qobject_cast<Latte::Corona *>(this->corona());
|
|
|
|
if (latteCorona && containments.size() > 0) {
|
|
Layout::GenericLayout *newLayout = latteCorona->layoutsManager()->synchronizer()->layout(layoutName);
|
|
|
|
if (newLayout) {
|
|
newLayout->assignToLayout(this, containments);
|
|
}
|
|
}
|
|
}
|
|
|
|
void View::hideWindowsForSlidingOut()
|
|
{
|
|
if (m_primaryConfigView) {
|
|
m_primaryConfigView->hideConfigWindow();
|
|
}
|
|
}
|
|
|
|
//!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);
|
|
|
|
for (const QString &appletName : appletNames) {
|
|
if (appletName == name)
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
Latte::Data::View View::data() const
|
|
{
|
|
Latte::Data::View vdata;
|
|
vdata.id = QString::number(containment()->id());
|
|
vdata.isActive = true;
|
|
vdata.onPrimary = onPrimary();
|
|
|
|
vdata.screen = containment()->screen();
|
|
if (!Layouts::Storage::isValid(vdata.screen)) {
|
|
vdata.screen = containment()->lastScreen();
|
|
}
|
|
|
|
vdata.edge = location();
|
|
vdata.maxLength = m_maxLength * 100;
|
|
vdata.alignment = m_alignment;
|
|
vdata.subcontainments = Layouts::Storage::self()->subcontainments(layout(), containment());
|
|
|
|
vdata.setState(Latte::Data::View::IsCreated);
|
|
return vdata;
|
|
}
|
|
|
|
QQuickItem *View::colorizer() const
|
|
{
|
|
return m_colorizer;
|
|
}
|
|
|
|
void View::setColorizer(QQuickItem *colorizer)
|
|
{
|
|
if (m_colorizer == colorizer) {
|
|
return;
|
|
}
|
|
|
|
m_colorizer = colorizer;
|
|
emit colorizerChanged();
|
|
}
|
|
|
|
ViewPart::Effects *View::effects() const
|
|
{
|
|
return m_effects;
|
|
}
|
|
|
|
ViewPart::Indicator *View::indicator() const
|
|
{
|
|
return m_indicator;
|
|
}
|
|
|
|
ViewPart::ContextMenu *View::contextMenu() const
|
|
{
|
|
return m_contextMenu;
|
|
}
|
|
|
|
ViewPart::ContainmentInterface *View::extendedInterface() const
|
|
{
|
|
return m_interface;
|
|
}
|
|
|
|
ViewPart::Parabolic *View::parabolic() const
|
|
{
|
|
return m_parabolic;
|
|
}
|
|
|
|
ViewPart::Positioner *View::positioner() const
|
|
{
|
|
return m_positioner;
|
|
}
|
|
|
|
ViewPart::EventsSink *View::sink() const
|
|
{
|
|
return m_sink;
|
|
}
|
|
|
|
ViewPart::VisibilityManager *View::visibility() const
|
|
{
|
|
return m_visibility;
|
|
}
|
|
|
|
ViewPart::WindowsTracker *View::windowsTracker() const
|
|
{
|
|
return m_windowsTracker;
|
|
}
|
|
|
|
Latte::Interfaces *View::interfacesGraphicObj() const
|
|
{
|
|
return m_interfacesGraphicObj;
|
|
}
|
|
|
|
void View::setInterfacesGraphicObj(Latte::Interfaces *ifaces)
|
|
{
|
|
if (m_interfacesGraphicObj == ifaces) {
|
|
return;
|
|
}
|
|
|
|
m_interfacesGraphicObj = ifaces;
|
|
|
|
if (containment()) {
|
|
QQuickItem *containmentGraphicItem = qobject_cast<QQuickItem *>(containment()->property("_plasma_graphicObject").value<QObject *>());
|
|
|
|
if (containmentGraphicItem) {
|
|
containmentGraphicItem->setProperty("_latte_view_interfacesobject", QVariant::fromValue(m_interfacesGraphicObj));
|
|
}
|
|
}
|
|
|
|
emit interfacesGraphicObjChanged();
|
|
}
|
|
|
|
bool View::event(QEvent *e)
|
|
{
|
|
QEvent *sunkevent = e;
|
|
|
|
if (!m_inDelete) {
|
|
emit eventTriggered(e);
|
|
|
|
bool sinkableevent{false};
|
|
|
|
switch (e->type()) {
|
|
case QEvent::Enter:
|
|
m_containsMouse = true;
|
|
break;
|
|
|
|
case QEvent::Leave:
|
|
m_containsMouse = false;
|
|
setContainsDrag(false);
|
|
sinkableevent = true;
|
|
break;
|
|
|
|
case QEvent::DragEnter:
|
|
setContainsDrag(true);
|
|
sinkableevent = true;
|
|
break;
|
|
|
|
case QEvent::DragLeave:
|
|
setContainsDrag(false);
|
|
break;
|
|
|
|
case QEvent::DragMove:
|
|
sinkableevent = true;
|
|
break;
|
|
|
|
case QEvent::Drop:
|
|
setContainsDrag(false);
|
|
sinkableevent = true;
|
|
break;
|
|
|
|
case QEvent::MouseMove:
|
|
sinkableevent = true;
|
|
break;
|
|
|
|
case QEvent::MouseButtonPress:
|
|
if (auto me = dynamic_cast<QMouseEvent *>(e)) {
|
|
emit mousePressed(me->pos(), me->button());
|
|
sinkableevent = true;
|
|
}
|
|
break;
|
|
|
|
case QEvent::MouseButtonRelease:
|
|
if (auto me = dynamic_cast<QMouseEvent *>(e)) {
|
|
emit mouseReleased(me->pos(), me->button());
|
|
sinkableevent = true;
|
|
}
|
|
break;
|
|
|
|
case QEvent::PlatformSurface:
|
|
if (auto pe = dynamic_cast<QPlatformSurfaceEvent *>(e)) {
|
|
switch (pe->surfaceEventType()) {
|
|
case QPlatformSurfaceEvent::SurfaceCreated:
|
|
setupWaylandIntegration();
|
|
|
|
if (m_shellSurface) {
|
|
//! immediateSyncGeometry helps avoiding binding loops from containment qml side
|
|
m_positioner->immediateSyncGeometry();
|
|
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;
|
|
|
|
case QEvent::Show:
|
|
if (m_visibility) {
|
|
m_visibility->initViewFlags();
|
|
}
|
|
break;
|
|
|
|
case QEvent::Wheel:
|
|
if (auto we = dynamic_cast<QWheelEvent *>(e)) {
|
|
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
|
|
QPoint pos = QPoint(we->x(), we->y());
|
|
#else
|
|
QPoint pos = we->position().toPoint();
|
|
#endif
|
|
emit wheelScrolled(pos, we->angleDelta(), we->buttons());
|
|
|
|
sinkableevent = true;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (sinkableevent && m_sink->isActive()) {
|
|
sunkevent = m_sink->onEvent(e);
|
|
}
|
|
}
|
|
|
|
return ContainmentView::event(sunkevent);
|
|
}
|
|
|
|
void View::releaseConfigView()
|
|
{
|
|
m_primaryConfigView = nullptr;
|
|
}
|
|
|
|
//! release grab and restore mouse state
|
|
void View::unblockMouse(int x, int y)
|
|
{
|
|
setMouseGrabEnabled(false);
|
|
|
|
m_releaseGrab_x = x;
|
|
m_releaseGrab_y = y;
|
|
m_releaseGrabTimer.start();
|
|
}
|
|
|
|
void View::releaseGrab()
|
|
{
|
|
//! ungrab mouse
|
|
if (mouseGrabberItem()) {
|
|
mouseGrabberItem()->ungrabMouse();
|
|
}
|
|
|
|
//! properly release grabbed mouse in order to inform all views
|
|
setMouseGrabEnabled(true);
|
|
setMouseGrabEnabled(false);
|
|
|
|
//! Send a fake QEvent::Leave to inform applets for mouse leaving the view
|
|
QHoverEvent e(QEvent::Leave, QPoint(-5,-5), QPoint(m_releaseGrab_x, m_releaseGrab_y));
|
|
QCoreApplication::instance()->sendEvent(this, &e);
|
|
}
|
|
|
|
QAction *View::action(const QString &name)
|
|
{
|
|
if (!containment()) {
|
|
return nullptr;
|
|
}
|
|
|
|
return this->containment()->actions()->action(name);
|
|
}
|
|
|
|
QVariantList View::containmentActions() const
|
|
{
|
|
QVariantList actions;
|
|
|
|
if (!containment()) {
|
|
return actions;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
for (QAction *ac : plugin->contextualActions()) {
|
|
actions << QVariant::fromValue<QAction *>(ac);
|
|
}
|
|
|
|
return actions;
|
|
}
|
|
|
|
bool View::isHighestPriorityView() {
|
|
if (m_layout) {
|
|
return this == m_layout->highestPriorityView();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//! BEGIN: WORKAROUND order to force top panels always on top and above left/right panels
|
|
void View::topViewAlwaysOnTop()
|
|
{
|
|
if (!m_visibility) {
|
|
return;
|
|
}
|
|
|
|
if (location() == Plasma::Types::TopEdge
|
|
&& m_visibility->mode() != Latte::Types::WindowsCanCover
|
|
&& m_visibility->mode() != Latte::Types::WindowsAlwaysCover) {
|
|
//! this is needed in order to preserve that the top dock will be above others.
|
|
//! Unity layout paradigm is a good example for this. The top panel shadow
|
|
//! should be always on top compared to left panel
|
|
m_visibility->setViewOnFrontLayer();
|
|
}
|
|
}
|
|
|
|
void View::verticalUnityViewHasFocus()
|
|
{
|
|
if (formFactor() == Plasma::Types::Vertical
|
|
&& (y() != screenGeometry().y())
|
|
&& ( (m_alignment == Latte::Types::Justify && m_maxLength == 1.0)
|
|
||(m_alignment == Latte::Types::Top && m_offset == 0.0) )) {
|
|
emit m_corona->verticalUnityViewHasFocus();
|
|
}
|
|
}
|
|
//! END: WORKAROUND
|
|
|
|
//!BEGIN overriding context menus behavior
|
|
void View::mousePressEvent(QMouseEvent *event)
|
|
{
|
|
bool result = m_contextMenu->mousePressEvent(event);
|
|
|
|
if (result) {
|
|
PlasmaQuick::ContainmentView::mousePressEvent(event);
|
|
updateTransientWindowsTracking();
|
|
}
|
|
|
|
verticalUnityViewHasFocus();
|
|
}
|
|
//!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.writeEntry("viewType", (int)m_type);
|
|
}
|
|
|
|
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
|