3
0
mirror of https://github.com/Qortal/Brooklyn.git synced 2025-02-07 14:54:17 +00:00
Brooklyn/plasma/workspace/krunner/view.cpp
2022-03-05 22:41:29 +05:00

387 lines
11 KiB
C++

/*
SPDX-FileCopyrightText: 2014 Marco Martin <mart@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "view.h"
#include <QAction>
#include <QClipboard>
#include <QDebug>
#include <QGuiApplication>
#include <QPlatformSurfaceEvent>
#include <QQmlContext>
#include <QQmlEngine>
#include <QQuickItem>
#include <QScreen>
#include <KAuthorized>
#include <KCrash>
#include <KIO/CommandLauncherJob>
#include <KLocalizedString>
#include <KService>
#include <KWindowEffects>
#include <KWindowSystem>
#include <kdeclarative/qmlobject.h>
#include <KPackage/Package>
#include <KPackage/PackageLoader>
#include <KWayland/Client/connection_thread.h>
#include <KWayland/Client/registry.h>
#include <KWayland/Client/surface.h>
#include "appadaptor.h"
View::View(QWindow *)
: PlasmaQuick::Dialog()
, m_offset(.5)
, m_floating(false)
{
setClearBeforeRendering(true);
setColor(QColor(Qt::transparent));
setFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
KCrash::initialize();
// used only by screen readers
setTitle(i18n("KRunner"));
m_config = KConfigGroup(KSharedConfig::openConfig(), "General");
m_stateData = KSharedConfig::openConfig(QStringLiteral("krunnerstaterc"), //
KConfig::NoGlobals,
QStandardPaths::GenericDataLocation)
->group("General");
m_configWatcher = KConfigWatcher::create(KSharedConfig::openConfig());
connect(m_configWatcher.data(), &KConfigWatcher::configChanged, this, [this](const KConfigGroup &group, const QByteArrayList &names) {
Q_UNUSED(names);
if (group.name() == QLatin1String("General")) {
loadConfig();
}
});
loadConfig();
new AppAdaptor(this);
QDBusConnection::sessionBus().registerObject(QStringLiteral("/App"), this);
m_qmlObj = new KDeclarative::QmlObject(this);
m_qmlObj->setInitializationDelayed(true);
connect(m_qmlObj, &KDeclarative::QmlObject::finished, this, &View::objectIncubated);
KPackage::Package package = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("Plasma/LookAndFeel"));
KConfigGroup cg(KSharedConfig::openConfig(), "KDE");
const QString packageName = cg.readEntry("LookAndFeelPackage", QString());
if (!packageName.isEmpty()) {
package.setPath(packageName);
}
m_qmlObj->engine()->rootContext()->setContextProperty(QStringLiteral("runnerWindow"), this);
m_qmlObj->setSource(package.fileUrl("runcommandmainscript"));
m_qmlObj->completeInitialization();
auto screenRemoved = [this](QScreen *screen) {
if (screen == this->screen()) {
setScreen(qGuiApp->primaryScreen());
hide();
}
};
auto screenAdded = [this](const QScreen *screen) {
connect(screen, &QScreen::geometryChanged, this, &View::screenGeometryChanged);
screenGeometryChanged();
};
const auto screens = QGuiApplication::screens();
for (QScreen *s : screens) {
screenAdded(s);
}
connect(qGuiApp, &QGuiApplication::screenAdded, this, screenAdded);
connect(qGuiApp, &QGuiApplication::screenRemoved, this, screenRemoved);
connect(KWindowSystem::self(), &KWindowSystem::workAreaChanged, this, &View::resetScreenPos);
connect(qGuiApp, &QGuiApplication::focusWindowChanged, this, &View::slotFocusWindowChanged);
}
View::~View()
{
}
void View::objectIncubated()
{
auto mainItem = qobject_cast<QQuickItem *>(m_qmlObj->rootObject());
connect(mainItem, &QQuickItem::widthChanged, this, &View::resetScreenPos);
setMainItem(mainItem);
}
void View::slotFocusWindowChanged()
{
if (!QGuiApplication::focusWindow() && !m_pinned) {
setVisible(false);
}
}
bool View::freeFloating() const
{
return m_floating;
}
void View::setFreeFloating(bool floating)
{
if (m_floating == floating) {
return;
}
m_floating = floating;
if (m_floating) {
setLocation(Plasma::Types::Floating);
} else {
setLocation(Plasma::Types::TopEdge);
}
positionOnScreen();
}
void View::loadConfig()
{
setFreeFloating(m_config.readEntry("FreeFloating", false));
setPinned(m_stateData.readEntry("Pinned", false));
}
bool View::event(QEvent *event)
{
if (KWindowSystem::isPlatformWayland() && event->type() == QEvent::Expose && !dynamic_cast<QExposeEvent *>(event)->region().isNull()) {
auto surface = KWayland::Client::Surface::fromWindow(this);
auto shellSurface = KWayland::Client::PlasmaShellSurface::get(surface);
if (shellSurface && isVisible()) {
shellSurface->setPanelBehavior(KWayland::Client::PlasmaShellSurface::PanelBehavior::WindowsGoBelow);
shellSurface->setRole(KWayland::Client::PlasmaShellSurface::Role::Panel);
shellSurface->setPanelTakesFocus(true);
}
}
const bool retval = Dialog::event(event);
// QXcbWindow overwrites the state in its show event. There are plans
// to fix this in 5.4, but till then we must explicitly overwrite it
// each time.
bool setState = event->type() == QEvent::Show;
if (event->type() == QEvent::PlatformSurface) {
setState = (static_cast<QPlatformSurfaceEvent *>(event)->surfaceEventType() == QPlatformSurfaceEvent::SurfaceCreated);
}
if (setState) {
KWindowSystem::setState(winId(), NET::SkipTaskbar | NET::SkipPager);
}
return retval;
}
void View::resizeEvent(QResizeEvent *event)
{
if (event->oldSize().width() != event->size().width()) {
positionOnScreen();
}
}
void View::showEvent(QShowEvent *event)
{
KWindowSystem::setOnAllDesktops(winId(), true);
Dialog::showEvent(event);
positionOnScreen();
requestActivate();
}
void View::screenGeometryChanged()
{
if (isVisible()) {
positionOnScreen();
}
}
void View::resetScreenPos()
{
if (isVisible() && !m_floating) {
positionOnScreen();
}
}
void View::positionOnScreen()
{
if (!m_requestedVisible) {
return;
}
QScreen *shownOnScreen = QGuiApplication::primaryScreen();
const auto screens = QGuiApplication::screens();
for (QScreen *screen : screens) {
if (screen->geometry().contains(QCursor::pos(screen))) {
shownOnScreen = screen;
break;
}
}
// in wayland, QScreen::availableGeometry() returns QScreen::geometry()
// we could get a better value from plasmashell
// BUG: 386114
auto message = QDBusMessage::createMethodCall("org.kde.plasmashell", "/StrutManager", "org.kde.PlasmaShell.StrutManager", "availableScreenRect");
message.setArguments({shownOnScreen->name()});
QDBusPendingCall call = QDBusConnection::sessionBus().asyncCall(message);
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, [this, watcher, shownOnScreen]() {
watcher->deleteLater();
QDBusPendingReply<QRect> reply = *watcher;
const QRect r = reply.isValid() ? reply.value() : shownOnScreen->availableGeometry();
if (m_floating && !m_customPos.isNull()) {
int x = qBound(r.left(), m_customPos.x(), r.right() - width());
int y = qBound(r.top(), m_customPos.y(), r.bottom() - height());
setPosition(x, y);
PlasmaQuick::Dialog::setVisible(true);
return;
}
const int w = width();
int x = r.left() + (r.width() * m_offset) - (w / 2);
int y = r.top();
if (m_floating) {
y += r.height() / 3;
}
x = qBound(r.left(), x, r.right() - width());
y = qBound(r.top(), y, r.bottom() - height());
setPosition(x, y);
PlasmaQuick::Dialog::setVisible(true);
if (m_floating) {
KWindowSystem::setOnDesktop(winId(), KWindowSystem::currentDesktop());
KWindowSystem::setType(winId(), NET::Normal);
// Turn the sliding effect off
setLocation(Plasma::Types::Floating);
} else {
KWindowSystem::setOnAllDesktops(winId(), true);
setLocation(Plasma::Types::TopEdge);
}
KWindowSystem::forceActiveWindow(winId());
});
}
void View::toggleDisplay()
{
if (isVisible() && !QGuiApplication::focusWindow()) {
KWindowSystem::forceActiveWindow(winId());
return;
}
setVisible(!isVisible());
}
void View::display()
{
setVisible(true);
}
void View::displaySingleRunner(const QString &runnerName)
{
setVisible(true);
m_qmlObj->rootObject()->setProperty("runner", runnerName);
m_qmlObj->rootObject()->setProperty("query", QString());
}
void View::displayWithClipboardContents()
{
setVisible(true);
m_qmlObj->rootObject()->setProperty("runner", QString());
m_qmlObj->rootObject()->setProperty("query", QGuiApplication::clipboard()->text(QClipboard::Selection));
}
void View::query(const QString &term)
{
setVisible(true);
m_qmlObj->rootObject()->setProperty("runner", QString());
m_qmlObj->rootObject()->setProperty("query", term);
}
void View::querySingleRunner(const QString &runnerName, const QString &term)
{
setVisible(true);
m_qmlObj->rootObject()->setProperty("runner", runnerName);
m_qmlObj->rootObject()->setProperty("query", term);
}
void View::switchUser()
{
QDBusConnection::sessionBus().asyncCall(QDBusMessage::createMethodCall(QStringLiteral("org.kde.ksmserver"),
QStringLiteral("/KSMServer"),
QStringLiteral("org.kde.KSMServerInterface"),
QStringLiteral("openSwitchUserDialog")));
}
void View::displayConfiguration()
{
const QString systemSettings = QStringLiteral("systemsettings");
const QStringList kcmToOpen = QStringList(QStringLiteral("kcm_plasmasearch"));
KIO::CommandLauncherJob *job = nullptr;
if (KService::serviceByDesktopName(systemSettings)) {
job = new KIO::CommandLauncherJob(QStringLiteral("systemsettings5"), kcmToOpen);
job->setDesktopName(systemSettings);
} else {
job = new KIO::CommandLauncherJob(QStringLiteral("kcmshell5"), kcmToOpen);
}
job->start();
}
bool View::canConfigure() const
{
return KAuthorized::authorizeControlModule(QStringLiteral("kcm_plasmasearch.desktop"));
}
void View::setVisible(bool visible)
{
m_requestedVisible = visible;
if (visible && !m_floating) {
positionOnScreen();
} else {
PlasmaQuick::Dialog::setVisible(visible);
}
}
bool View::pinned() const
{
return m_pinned;
}
void View::setPinned(bool pinned)
{
if (m_pinned != pinned) {
m_pinned = pinned;
m_stateData.writeEntry("Pinned", pinned);
Q_EMIT pinnedChanged();
}
}
void View::removeFromHistory(int index)
{
if (m_manager) {
m_manager->removeFromHistory(index);
Q_EMIT historyChanged();
}
}
QStringList View::history() const
{
return m_manager ? m_manager->history() : QStringList();
}