mirror of https://gitee.com/openkylin/kwin.git
[Tablet] tablet mode manager refactoring
平板模式对不能最大化的窗口增加了毛玻璃背景
This commit is contained in:
parent
667ab29467
commit
08b7688125
|
@ -119,6 +119,7 @@ set(kwin_SRCS
|
|||
surfaceitem_wayland.cpp
|
||||
surfaceitem_x11.cpp
|
||||
syncalarmx11filter.cpp
|
||||
tablet_manager.cpp
|
||||
tablet_input.cpp
|
||||
toplevel.cpp
|
||||
hide_cursor_spy.cpp
|
||||
|
|
|
@ -96,7 +96,6 @@ AbstractClient::AbstractClient()
|
|||
connect(ApplicationMenu::self(), &ApplicationMenu::applicationMenuEnabledChanged, this, [this] {
|
||||
Q_EMIT hasApplicationMenuChanged(hasApplicationMenu());
|
||||
});
|
||||
m_bTabletToPcRestoreFlag = false;
|
||||
}
|
||||
|
||||
AbstractClient::~AbstractClient()
|
||||
|
@ -271,8 +270,12 @@ Layer AbstractClient::belongsToLayer() const
|
|||
// and the docks move into the NotificationLayer (which is between Above- and
|
||||
// ActiveLayer, so that active fullscreen windows will still cover everything)
|
||||
// Since the desktop is also activated, nothing should be in the ActiveLayer, though
|
||||
if (isInternal())
|
||||
if (isInternal()) {
|
||||
if (keepBelow()) {
|
||||
return BelowLayer;
|
||||
}
|
||||
return UnmanagedLayer;
|
||||
}
|
||||
if (isLockScreen())
|
||||
return UnmanagedLayer;
|
||||
if (isInputMethod())
|
||||
|
@ -933,6 +936,9 @@ bool AbstractClient::startInteractiveMoveResize()
|
|||
Q_ASSERT(QWidget::keyboardGrabber() == nullptr);
|
||||
Q_ASSERT(QWidget::mouseGrabber() == nullptr);
|
||||
stopDelayedInteractiveMoveResize();
|
||||
if (workspace()->isInTabletMode()) {
|
||||
return false;
|
||||
}
|
||||
if (QApplication::activePopupWidget() != nullptr)
|
||||
return false; // popups have grab
|
||||
if (isFullScreen() && (screens()->count() < 2 || !isMovableAcrossScreens()))
|
||||
|
@ -1130,9 +1136,6 @@ void AbstractClient::handleInteractiveMoveResize(int x, int y, int x_root, int y
|
|||
if (isWaitingForInteractiveMoveResizeSync())
|
||||
return; // we're still waiting for the client or the timeout
|
||||
|
||||
if (workspace()->isInTabletMode())
|
||||
return;
|
||||
|
||||
const Gravity gravity = interactiveMoveResizeGravity();
|
||||
if ((gravity == Gravity::None && !isMovableAcrossScreens())
|
||||
|| (gravity != Gravity::None && (isShade() || !isResizable()))) {
|
||||
|
@ -2390,16 +2393,15 @@ void AbstractClient::processDecorationMove(const QPoint &localPos, const QPoint
|
|||
|
||||
bool AbstractClient::processDecorationButtonPress(QMouseEvent *event, bool ignoreMenu)
|
||||
{
|
||||
// 标题栏鼠标或手指双击操作
|
||||
if (workspace()->isInTabletMode()) {
|
||||
return true;
|
||||
}
|
||||
Options::MouseCommand com = Options::MouseNothing;
|
||||
bool active = isActive();
|
||||
if (!wantsInput()) // we cannot be active, use it anyway
|
||||
active = true;
|
||||
|
||||
if(workspace()->isInTabletMode()) {
|
||||
Workspace::self()->performWindowOperation(this, Options::NoOp);
|
||||
return false;
|
||||
}
|
||||
|
||||
// check whether it is a double click
|
||||
if (event->button() == Qt::LeftButton && titlebarPositionUnderMouse()) {
|
||||
if (m_decoration.doubleClickTimer.isValid()) {
|
||||
|
@ -2795,51 +2797,6 @@ void AbstractClient::evaluateWindowRules()
|
|||
applyWindowRules();
|
||||
}
|
||||
|
||||
// 使工作区其他窗口最小化
|
||||
void AbstractClient::makeOthersMinimize()
|
||||
{
|
||||
printf("AbstractClient::makeOthersMinimize, takefocus windowType(0):%d, caption:%s, isModal:%d, isMaximizable:%d\n", windowType(), this->caption().toStdString().c_str(), isModal(), isMaximizable());
|
||||
qDebug() << "AbstractClient::makeOthersMinimize, takefocus windowType(0): " << windowType()
|
||||
<< ", caption: " << this->caption()
|
||||
<< ", isModal: " << isModal()
|
||||
<< ", isMaximizable: " << isMaximizable();
|
||||
//平板模式下,如果是isModal窗口(如xournal应用); 或者是瞬态的对话框(如归档管理器的新建窗口); 则没必要最小化其他所有未最小化的窗口,或者是新激活的桌面开始菜单和Dock窗口(比如onboard),也不要最小化其他窗口
|
||||
if (true == this->isUtility()
|
||||
|| true == this->isModal()
|
||||
|| (true == this->isDialog() && true == this->isTransient())
|
||||
|| true == this->isDesktop()
|
||||
|| true == this->isDock()
|
||||
|| caption().contains("sogou", Qt::CaseInsensitive)
|
||||
|| caption().contains("sidebar", Qt::CaseInsensitive)
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this->maximize(MaximizeFull);
|
||||
|
||||
printf("AbstractClient::makeOthersMinimize, takefocus windowType(1):%d, caption:%s, isdialog:%d, isMaximizable:%d\n", windowType(), this->caption().toStdString().c_str(), isDialog(), isMaximizable());
|
||||
|
||||
//锁屏时,如果当前是屏保窗口,对其他窗口不要最小化。解决在平板模式打开应用,锁屏后再进入桌面,应用窗口最小化问题
|
||||
if (this->resourceClass() == "ukui-screensaver-default") {
|
||||
return;
|
||||
}
|
||||
|
||||
for (AbstractClient *c : workspace()->allClientList()) {
|
||||
bool isIgnoreWindow = (this == c || c->isDock() || skipTaskbar() || c->isDialog() || c->isDesktop());
|
||||
bool isTabletBgWindow = (c->isUtility() && c->caption() == "ukui-kwin_tablet_background" && c->keepBelow());
|
||||
//除了自己,dock和对话框也没必要最小化
|
||||
if (isIgnoreWindow || isTabletBgWindow) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (false == c->isMinimized()){
|
||||
printf("AbstractClient::makeOthersMinimize, minimize unminimized caption:%s\n", c->caption().toStdString().c_str());
|
||||
c->minimize(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of activities the client window is on.
|
||||
* if it's on all activities, the list will be empty.
|
||||
|
|
|
@ -371,12 +371,13 @@ public:
|
|||
return m_icon;
|
||||
}
|
||||
|
||||
void setTabletToPcRestoreFlag(bool bTabletToPcRestoreFlag){
|
||||
m_bTabletToPcRestoreFlag = bTabletToPcRestoreFlag;
|
||||
// only on X11
|
||||
void setDisableActive() {
|
||||
Q_ASSERT(!m_diableActive);
|
||||
m_diableActive = true;
|
||||
}
|
||||
|
||||
bool getTabletToPcRestoreFlag() const {
|
||||
return m_bTabletToPcRestoreFlag;
|
||||
bool isDisableActive() const {
|
||||
return m_diableActive;
|
||||
}
|
||||
|
||||
bool isZombie() const;
|
||||
|
@ -578,7 +579,6 @@ public:
|
|||
void evaluateWindowRules();
|
||||
virtual void applyWindowRules();
|
||||
virtual bool takeFocus() = 0;
|
||||
void makeOthersMinimize();
|
||||
virtual bool wantsInput() const = 0;
|
||||
/**
|
||||
* Whether a dock window wants input.
|
||||
|
@ -637,6 +637,7 @@ public:
|
|||
void keepInArea(QRect area, bool partial = false);
|
||||
virtual QSize minSize() const;
|
||||
virtual QSize maxSize() const;
|
||||
void updateGeometryRestore();
|
||||
|
||||
/**
|
||||
* How to resize the window in order to obey constraints (mainly aspect ratios).
|
||||
|
@ -1242,13 +1243,13 @@ private:
|
|||
bool m_skipPager = false;
|
||||
bool m_skipSwitcher = false;
|
||||
QIcon m_icon;
|
||||
bool m_diableActive = false;
|
||||
bool m_active = false;
|
||||
bool m_zombie = false;
|
||||
bool m_keepAbove = false;
|
||||
bool m_keepBelow = false;
|
||||
bool m_demandsAttention = false;
|
||||
bool m_minimized = false;
|
||||
bool m_bTabletToPcRestoreFlag; //平板切换pc后,如果此时窗口处于最小化,则该标志置为true,激活后用于将最大化窗口还原,再次为false
|
||||
QTimer *m_autoRaiseTimer = nullptr;
|
||||
QTimer *m_shadeHoverTimer = nullptr;
|
||||
ShadeMode m_shadeMode = ShadeNone;
|
||||
|
@ -1366,6 +1367,11 @@ inline void AbstractClient::setPendingMoveResizeMode(MoveResizeMode mode)
|
|||
m_pendingMoveResizeMode = MoveResizeMode(uint(m_pendingMoveResizeMode) | uint(mode));
|
||||
}
|
||||
|
||||
inline void AbstractClient::updateGeometryRestore()
|
||||
{
|
||||
setGeometryRestore(frameGeometry());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(KWin::AbstractClient*)
|
||||
|
|
|
@ -1071,7 +1071,7 @@ void X11Client::focusInEvent(xcb_focus_in_event_t *e)
|
|||
// check if this client is in should_get_focus list or if activation is allowed
|
||||
bool activate = workspace()->allowClientActivation(this, -1U, true);
|
||||
workspace()->gotFocusIn(this); // remove from should_get_focus list
|
||||
if (activate) {
|
||||
if (activate && !isDisableActive()) {
|
||||
setActive(true);
|
||||
} else {
|
||||
if (workspace()->restoreFocus()) {
|
||||
|
|
|
@ -49,6 +49,9 @@ InternalClient::InternalClient(QWindow *window)
|
|||
setOnAllDesktops(true);
|
||||
setOpacity(m_internalWindow->opacity());
|
||||
setSkipCloseAnimation(m_internalWindow->property(s_skipClosePropertyName).toBool());
|
||||
if (m_internalWindowFlags.testFlag(Qt::WindowStaysOnBottomHint)) {
|
||||
setKeepBelow(true);
|
||||
}
|
||||
|
||||
// Create scene window, effect window, and update server-side shadow.
|
||||
setupCompositing();
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "main.h"
|
||||
// kwin
|
||||
#include "tablet_manager.h"
|
||||
#include "platform.h"
|
||||
#include "atoms.h"
|
||||
#ifdef KWIN_BUILD_CMS
|
||||
|
@ -149,6 +150,7 @@ void Application::start()
|
|||
m_kxkbConfig = KSharedConfig::openConfig(QStringLiteral("kxkbrc"), KConfig::NoGlobals);
|
||||
}
|
||||
|
||||
KWin::TabletManager::create(this);
|
||||
performStartup();
|
||||
}
|
||||
|
||||
|
|
|
@ -259,8 +259,12 @@ void WinInfo::changeState(NET::States state, NET::States mask)
|
|||
|
||||
if ((mask & NET::FullScreen) != 0 && (state & NET::FullScreen) == 0)
|
||||
m_client->setFullScreen(false, false);
|
||||
if ((mask & NET::Max) == NET::Max)
|
||||
m_client->setMaximize(state & NET::MaxVert, state & NET::MaxHoriz);
|
||||
if ((mask & NET::Max) == NET::Max) {
|
||||
// gtk 应用标题栏下面的菜单栏可拖动区域触摸操作时会触发
|
||||
if (!workspace()->isInTabletMode()) {
|
||||
m_client->setMaximize(state & NET::MaxVert, state & NET::MaxHoriz);
|
||||
}
|
||||
}
|
||||
else if (mask & NET::MaxVert)
|
||||
m_client->setMaximize(state & NET::MaxVert, m_client->maximizeMode() & MaximizeHorizontal);
|
||||
else if (mask & NET::MaxHoriz)
|
||||
|
|
|
@ -830,11 +830,10 @@ void AbstractClient::shrinkVertical()
|
|||
|
||||
void Workspace::quickTileWindow(QuickTileMode mode)
|
||||
{
|
||||
if (!active_client) {
|
||||
if (workspace()->isInTabletMode()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_bTabletMode) {
|
||||
if (!active_client) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,807 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2022 KylinSoft Co., Ltd.
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "tablet_manager.h"
|
||||
#include "composite.h"
|
||||
#include "internal_client.h"
|
||||
#include "main.h"
|
||||
#include "screens.h"
|
||||
#include "scene.h"
|
||||
#include "unmanaged.h"
|
||||
#include "wayland_server.h"
|
||||
#include "workspace.h"
|
||||
#include "x11client.h"
|
||||
#include "abstract_wayland_output.h"
|
||||
#include "effects.h"
|
||||
#include "effectloader.h"
|
||||
#include <kwineffects.h>
|
||||
|
||||
// Qt
|
||||
#include <QDBusMessage>
|
||||
#include <QDBusConnection>
|
||||
#include <QStyleOption>
|
||||
#include <QPainter>
|
||||
#include <QX11Info>
|
||||
#include <QFile>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
static const QString BLUR_EFFECT_NAME = "blur";
|
||||
static const QString TRANSLUCENCY_EFFECT_NAME = "kwin4_effect_translucency";
|
||||
static const QString SCALEDESKTOP_EFFECT_NAME = "kwin4_effect_scaledesktop";
|
||||
static const QString KYLIN_STATUSMANAGER_SERVICE = "com.kylin.statusmanager.interface";
|
||||
static const QString KYLIN_STATUSMANAGER_PATH = "/";
|
||||
static const QString KYLIN_STATUSMANAGER_INTERFACE = "com.kylin.statusmanager.interface";
|
||||
|
||||
KWIN_SINGLETON_FACTORY(TabletManager)
|
||||
|
||||
TabletManager::TabletManager(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_background(new TabletBackground())
|
||||
, m_singleWinManager(nullptr)
|
||||
, m_bTabletMode(false)
|
||||
, m_existTabletDesktop(false)
|
||||
, m_effects(nullptr)
|
||||
, m_effectloader(nullptr)
|
||||
{
|
||||
m_existTabletDesktop = QFile::exists(QStringLiteral("/usr/bin/ukui-tablet-desktop"));
|
||||
if (kwinApp()->operationMode() == Application::OperationMode::OperationModeX11) {
|
||||
// TODO: 在这块如果不设置窗口可见和背景模糊的话,X 下无法创建成功窗口并受窗管控制
|
||||
m_background->show();
|
||||
// KWindowEffects::enableBlurBehind(m_background->windowHandle(), true);
|
||||
setBlurBehind();
|
||||
}
|
||||
// Workspace is created after the wayland server is initialized.
|
||||
connect(kwinApp(), &Application::workspaceCreated, this, &TabletManager::init);
|
||||
}
|
||||
|
||||
TabletManager::~TabletManager()
|
||||
{
|
||||
// TODO: 此处调用析构会导致double free
|
||||
// if (m_background) {
|
||||
// delete m_background;
|
||||
// m_background = nullptr;
|
||||
// }
|
||||
if (m_singleWinManager) {
|
||||
delete m_singleWinManager;
|
||||
m_singleWinManager = nullptr;
|
||||
}
|
||||
m_effectloader = nullptr;
|
||||
m_effects = nullptr;
|
||||
}
|
||||
|
||||
void TabletManager::init()
|
||||
{
|
||||
if (m_background) {
|
||||
m_background->init();
|
||||
}
|
||||
|
||||
// 延迟一个事件循环再初始化单窗口管理模块类对象,因为混成类是在Workspace的构造函数中调用的,而混成在启动函数中
|
||||
// 调用了 Workspace::self() 函数 ,所以混成类延迟了一个事件循环来保证Worksapce构造完成。因此此处也需要延迟
|
||||
// 一个事件循环来确保在特效启动过程中模糊特效插件已经加载完成。不然在 X11 环境下太早对背景窗口最小化会导致模糊失败。
|
||||
// 在这里使用混成的信号 compositingToggled(bool) 不是很合适,因为混成无法开启时,不会触发此信号。
|
||||
QTimer::singleShot(0, [this]() {
|
||||
if (!m_singleWinManager) {
|
||||
m_singleWinManager = new SingleWindowManager(this);
|
||||
m_singleWinManager->setBlurBackground(m_background);
|
||||
}
|
||||
});
|
||||
connect(Compositor::self(), &Compositor::compositingToggled, [this](bool active) {
|
||||
if (active) {
|
||||
m_effects = static_cast<EffectsHandlerImpl*>(effects);
|
||||
m_effectloader = m_effects->findChild<AbstractEffectLoader*>();
|
||||
connect(m_effectloader, &AbstractEffectLoader::effectLoaded, [this](KWin::Effect *effect, const QString &name){
|
||||
Q_UNUSED(effect)
|
||||
if (name == BLUR_EFFECT_NAME || name == TRANSLUCENCY_EFFECT_NAME) {
|
||||
m_background->update();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
m_effectloader = nullptr;
|
||||
m_effects = nullptr;
|
||||
}
|
||||
});
|
||||
|
||||
QDBusMessage message = QDBusMessage::createMethodCall(KYLIN_STATUSMANAGER_SERVICE,
|
||||
KYLIN_STATUSMANAGER_PATH,
|
||||
KYLIN_STATUSMANAGER_INTERFACE,
|
||||
QStringLiteral("get_current_tabletmode"));
|
||||
QDBusMessage response = QDBusConnection::sessionBus().call(message);
|
||||
if (response.type() == QDBusMessage::ReplyMessage) {
|
||||
bool bTabletMode = response.arguments().takeFirst().toBool();
|
||||
slotSwitchTabletMode(bTabletMode);
|
||||
} else {
|
||||
printf("TabletMode qdus invalid\n");
|
||||
}
|
||||
|
||||
QDBusConnection::sessionBus().connect(KYLIN_STATUSMANAGER_SERVICE,
|
||||
KYLIN_STATUSMANAGER_PATH,
|
||||
KYLIN_STATUSMANAGER_INTERFACE,
|
||||
QStringLiteral("mode_change_signal"),
|
||||
this,
|
||||
SLOT(slotSwitchTabletMode(bool)));
|
||||
}
|
||||
|
||||
void TabletManager::slotSwitchTabletMode(bool bSurfaceMode)
|
||||
{
|
||||
if (m_bTabletMode == bSurfaceMode) {
|
||||
return;
|
||||
}
|
||||
m_bTabletMode = bSurfaceMode;
|
||||
Q_EMIT tabletModeChanged(m_bTabletMode);
|
||||
|
||||
if (m_singleWinManager) {
|
||||
if (KWin::effects) {
|
||||
EffectsHandlerImpl *effect = static_cast<EffectsHandlerImpl *>(effects);
|
||||
bool isLoad = effect->isEffectLoaded(SCALEDESKTOP_EFFECT_NAME);
|
||||
qDebug() << __func__ << "kwin4_effect_scaledesktop is loaded: " << isLoad;
|
||||
if (isLoad && existTabletDesktop()) {
|
||||
// 桌面缩放动作需要 1000 ms
|
||||
QTimer::singleShot(1000, [this]() {
|
||||
m_singleWinManager->switchTablet(m_bTabletMode);
|
||||
});
|
||||
} else {
|
||||
m_singleWinManager->switchTablet(m_bTabletMode);
|
||||
}
|
||||
} else {
|
||||
qDebug() << __func__ << "KWin::effects pointer is not initialized ! ! !";
|
||||
m_singleWinManager->switchTablet(m_bTabletMode);
|
||||
}
|
||||
}
|
||||
|
||||
// 在平板模式启动 kwin 时,此时 effects 对象还未初始化,此时也没有必要进行窗口移动
|
||||
if (KWin::effects == nullptr) {
|
||||
return;
|
||||
}
|
||||
const auto stacking_order = workspace()->stackingOrder();
|
||||
for (auto it = stacking_order.rbegin(); it != stacking_order.rend(); ++it) {
|
||||
AbstractClient *c = qobject_cast<AbstractClient*>(*it);
|
||||
// 因为现在侧边栏没有设置skipXXX等属性,所以暂时使用标题栏名字判断
|
||||
if (!c || c->isDock() || c->isDesktop()) {
|
||||
continue;
|
||||
}
|
||||
if (m_bTabletMode) {
|
||||
m_windowDesktopMap.insert(c->internalId(), c->desktop());
|
||||
// Tablet 模式下所有工作区的窗口合并到一起
|
||||
moveWindowBetweenVDesktop(c->internalId(), c->desktop(), KWin::effects->currentDesktop());
|
||||
} else {
|
||||
if (m_windowDesktopMap.contains(c->internalId())) {
|
||||
// PC 模式下窗口还原到原来所在的工作区
|
||||
moveWindowBetweenVDesktop(c->internalId(), KWin::effects->currentDesktop(), m_windowDesktopMap.value(c->internalId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!m_bTabletMode) {
|
||||
m_windowDesktopMap.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void TabletManager::moveWindowBetweenVDesktop(QUuid windowId, int srcDesktopIndex, int destDesktopIndex)
|
||||
{
|
||||
auto* window = KWin::effects->findWindow(windowId);
|
||||
if (window == nullptr || window->isOnAllDesktops()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto desktopIndexList = window->desktops();
|
||||
if (!desktopIndexList.contains(srcDesktopIndex)) {
|
||||
return;
|
||||
}
|
||||
|
||||
desktopIndexList.remove(desktopIndexList.indexOf(srcDesktopIndex));
|
||||
|
||||
if (desktopIndexList.contains(destDesktopIndex)) {
|
||||
return;
|
||||
}
|
||||
|
||||
desktopIndexList.append(destDesktopIndex);
|
||||
|
||||
KWin::effects->windowToDesktops(window, desktopIndexList);
|
||||
}
|
||||
|
||||
void TabletManager::toggleTabletMode()
|
||||
{
|
||||
QDBusMessage call = QDBusMessage::createMethodCall(KYLIN_STATUSMANAGER_SERVICE,
|
||||
KYLIN_STATUSMANAGER_PATH,
|
||||
KYLIN_STATUSMANAGER_INTERFACE,
|
||||
QStringLiteral("set_tabletmode"));
|
||||
call.setArguments({!m_bTabletMode, "kwin", "debug"});
|
||||
QDBusMessage response = QDBusConnection::sessionBus().call(call);
|
||||
if (response.type() != QDBusMessage::ReplyMessage) {
|
||||
qWarning() << "[=== checkmode ===]" << "set_tabletmode dbus not work, change locally";
|
||||
slotSwitchTabletMode(!m_bTabletMode);
|
||||
}
|
||||
}
|
||||
|
||||
void TabletManager::setBlurBehind(double radius)
|
||||
{
|
||||
if (kwinApp()->operationMode() == Application::OperationMode::OperationModeX11) {
|
||||
xcb_connection_t *c = QX11Info::connection();
|
||||
if (!c) {
|
||||
return;
|
||||
}
|
||||
const QByteArray effectName = QByteArrayLiteral("_KDE_NET_WM_BLUR_BEHIND_REGION");
|
||||
xcb_intern_atom_cookie_t atomCookie = xcb_intern_atom_unchecked(c, false, effectName.length(), effectName.constData());
|
||||
QScopedPointer<xcb_intern_atom_reply_t, QScopedPointerPodDeleter> atom(xcb_intern_atom_reply(c, atomCookie, nullptr));
|
||||
if (!atom) {
|
||||
return;
|
||||
}
|
||||
|
||||
QVector<uint32_t> data;
|
||||
QRegion region;
|
||||
data.reserve(region.rectCount() * 4 + 1); // 1 means radius
|
||||
for (const QRect &r : region) {
|
||||
// kwin on X uses device pixels, convert from logical
|
||||
auto dpr = qApp->devicePixelRatio();
|
||||
data << r.x() * dpr << r.y() * dpr << r.width() * dpr << r.height() * dpr;
|
||||
}
|
||||
data << radius;
|
||||
xcb_change_property(c, XCB_PROP_MODE_REPLACE, m_background->winId(), atom->atom, XCB_ATOM_CARDINAL, 32, data.size(), data.constData());
|
||||
} else {
|
||||
if (m_background && m_background->windowHandle()) {
|
||||
m_background->windowHandle()->setProperty("kwin_blur_strength", radius);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TabletManager::showBackground(double radius)
|
||||
{
|
||||
if (!m_singleWinManager) {
|
||||
return;
|
||||
}
|
||||
m_singleWinManager->showBackground();
|
||||
setBlurBehind(radius);
|
||||
}
|
||||
|
||||
void TabletManager::hideBackground(double radius)
|
||||
{
|
||||
if (!m_singleWinManager) {
|
||||
return;
|
||||
}
|
||||
m_singleWinManager->hideBackground();
|
||||
setBlurBehind(radius);
|
||||
}
|
||||
|
||||
TabletBackground::TabletBackground()
|
||||
: QWidget()
|
||||
{
|
||||
if (kwinApp()->operationMode() == Application::OperationMode::OperationModeX11) {
|
||||
setWindowFlags(Qt::WindowStaysOnBottomHint | Qt::FramelessWindowHint);
|
||||
} else {
|
||||
setWindowFlags(Qt::BypassWindowManagerHint | Qt::WindowStaysOnBottomHint | Qt::FramelessWindowHint);
|
||||
}
|
||||
setAttribute(Qt::WA_ShowWithoutActivating);
|
||||
setAttribute(Qt::WA_TranslucentBackground);
|
||||
setFocusPolicy(Qt::NoFocus);
|
||||
setWindowTitle("tablet_blur_background");
|
||||
}
|
||||
|
||||
TabletBackground::~TabletBackground()
|
||||
{
|
||||
qDebug() << __func__;
|
||||
}
|
||||
|
||||
void TabletBackground::init()
|
||||
{
|
||||
slotGeometryChanged();
|
||||
connect(screens(), &Screens::geometryChanged, this, &TabletBackground::slotGeometryChanged);
|
||||
}
|
||||
|
||||
void TabletBackground::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
QStyleOption opt;
|
||||
opt.init(this);
|
||||
QPainter p(this);
|
||||
p.setPen(Qt::NoPen);
|
||||
// QColor color = qApp->palette().color(QPalette::Base);
|
||||
QColor color(64, 64, 64);
|
||||
// color.setAlpha(m_alpha);
|
||||
bool isShouldBlur = false;
|
||||
if (effects) {
|
||||
EffectsHandlerImpl *effect = static_cast<EffectsHandlerImpl *>(effects);
|
||||
bool isLoadBlurEffect = effect->isEffectLoaded(BLUR_EFFECT_NAME);
|
||||
qDebug() << __func__ << isLoadBlurEffect;
|
||||
if ( isLoadBlurEffect) {
|
||||
isShouldBlur = true;
|
||||
} else {
|
||||
isShouldBlur = false;
|
||||
}
|
||||
}
|
||||
if (isShouldBlur) {
|
||||
color.setAlpha(0);
|
||||
} else {
|
||||
color.setAlpha(255);
|
||||
}
|
||||
QPalette pal(this->palette());
|
||||
pal.setColor(QPalette::Window, QColor(color));
|
||||
this->setPalette(pal);
|
||||
QBrush brush = QBrush(color);
|
||||
p.setBrush(brush);
|
||||
p.drawRoundedRect(opt.rect, 0, 0);
|
||||
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
|
||||
}
|
||||
|
||||
void TabletBackground::slotGeometryChanged()
|
||||
{
|
||||
qDebug() << __func__ << screens()->geometry();
|
||||
QRect screenGeo = screens()->geometry();
|
||||
setGeometry(screenGeo);
|
||||
setFixedSize(screenGeo.size());
|
||||
}
|
||||
|
||||
SingleWindowManager::SingleWindowManager(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_blurHelperWindow(nullptr)
|
||||
, m_blurBackground(nullptr)
|
||||
, m_ignorePlaceCenterList()
|
||||
, m_bTabletMode(false)
|
||||
{
|
||||
// 蓝牙、网络工具、搜索不需要进行居中处理
|
||||
m_ignorePlaceCenterList << "ukui-bluetooth" << "kylin-nm" << "ukui-search";
|
||||
connect(workspace(), &Workspace::clientAdded, this, &SingleWindowManager::handleClientAdded);
|
||||
connect(workspace(), &Workspace::clientRemoved, this, &SingleWindowManager::handleClientRemoved);
|
||||
connect(workspace(), &Workspace::clientActivated, this, &SingleWindowManager::handleClientActivated);
|
||||
connect(workspace(), &Workspace::clientMinimizedChanged, this, &SingleWindowManager::handleClientMinimizedChanged);
|
||||
//connect(workspace(), &Workspace::clientDemandsAttentionChanged, this, &SingleWindowManager::handleClientAdded);
|
||||
connect(screens(), &Screens::geometryChanged, this, &SingleWindowManager::handleScreenGeometryChanged);
|
||||
}
|
||||
|
||||
SingleWindowManager::~SingleWindowManager() = default;
|
||||
|
||||
void SingleWindowManager::setBlurBackground(TabletBackground *blurBackground)
|
||||
{
|
||||
if (!blurBackground) {
|
||||
return;
|
||||
}
|
||||
m_blurBackground = blurBackground;
|
||||
if (!m_blurHelperWindow && m_blurBackground) {
|
||||
const auto stacking_order = workspace()->stackingOrder();
|
||||
if (!stacking_order.isEmpty()) {
|
||||
for (int i = stacking_order.count() - 1; i > -1; --i) {
|
||||
AbstractClient *c = qobject_cast<AbstractClient*>(stacking_order.at(i));
|
||||
if (c && c->keepBelow() && c->caption().contains("tablet_blur_background")) {
|
||||
m_blurHelperWindow = c;
|
||||
// 设置毛玻璃背景窗口为全屏,防止在updateClientArea()->checkWorkspacePosition()时毛玻璃窗口被修改位置
|
||||
m_blurHelperWindow->setFullScreen(true, false);
|
||||
// only on X11
|
||||
m_blurHelperWindow->setDisableActive();
|
||||
m_blurHelperWindow->setSkipSwitcher(true);
|
||||
m_blurHelperWindow->setSkipPager(true);
|
||||
m_blurHelperWindow->setOriginalSkipTaskbar(true);
|
||||
m_blurHelperWindow->minimize(true);
|
||||
connect(Compositor::self(), &Compositor::compositingToggled, [this](bool active){
|
||||
if (active) {
|
||||
if (m_blurHelperWindow->effectWindow()) {
|
||||
m_blurHelperWindow->effectWindow()->setData(WindowForceBlurRole, QVariant(true));
|
||||
}
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// kwin 启动时如果存在已经存在的窗口,需要进行判断是否需要将顶层最大化或者显示桌面
|
||||
switchTablet(TabletManager::self()->tabletMode());
|
||||
}
|
||||
|
||||
void SingleWindowManager::switchTablet(bool bTabletMode)
|
||||
{
|
||||
m_bTabletMode = bTabletMode;
|
||||
const auto stacking_order = workspace()->stackingOrder();
|
||||
if (stacking_order.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool isTopWindowFound = false;
|
||||
bool isTopWindowMaximized = true;
|
||||
for (int i = stacking_order.count() - 1; i > -1; --i) {
|
||||
AbstractClient *c = qobject_cast<AbstractClient*>(stacking_order.at(i));
|
||||
if (!c) {
|
||||
continue;
|
||||
}
|
||||
if (TabletManager::self()->existTabletDesktop() && c->isDesktop()) {
|
||||
updateDesktopVisibleState(c);
|
||||
}
|
||||
// 侧边栏唤醒时不需要显示毛玻璃背景,侧边栏会自己绘制毛玻璃,所以使用标题栏名字将侧边栏移除
|
||||
if (c->isDock() || c->isDesktop() || c->caption().contains(QStringLiteral("sidebar")) || c->caption() == QStringLiteral("tablet-taskbar")) {
|
||||
continue;
|
||||
}
|
||||
#ifndef QT_NO_DEBUG
|
||||
qDebug() << "SingleWindowManager::switchTablet, caption:" << c->caption() << m_bTabletMode << "WindowType: " << c->windowType()
|
||||
<< "isModal: " << c->isModal() << "isDialog: " << c->isDialog() << "isSkipPager:" << c->skipPager()
|
||||
<< "isSkipSwitcher: " << c->skipSwitcher() << "isSkipTaskbar: " << c->skipSwitcher();
|
||||
#endif
|
||||
if (m_bTabletMode) { // PC to Tablet
|
||||
if (!c->isMinimized()) {
|
||||
if (!isTopWindowFound) {
|
||||
// 瞬态窗口
|
||||
if (c->isTransient()) {
|
||||
Placement::self()->placeCentered(c, workspace()->activeOutput()->geometry());
|
||||
// 模式却换时更新一下还原状态的geometry是为了防止居中后,在updateClientArea()时又被移动到PC模式保存的位置(不再居中显示)
|
||||
c->updateGeometryRestore();
|
||||
isTopWindowMaximized = false;
|
||||
if (c->mainClients().size() > 0) {
|
||||
isTopWindowFound = false;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
// 系统应用-文件保护箱的鉴权窗口比较特殊,是文件保护箱自己实现的。鉴权通过后才会显示文件保护箱主界面窗口,显示
|
||||
// 鉴权窗口时,鉴权窗口的属性为瞬态窗口,但是主界面窗口不存在。所以特种情况,需要将 isTopWindowFound 设为 true。
|
||||
isTopWindowFound = true;
|
||||
continue;
|
||||
}
|
||||
} else { // 主界面窗口
|
||||
isTopWindowFound = true;
|
||||
c->maximize(MaximizeFull); //序号越大,越在顶层,只需要将既不是任务栏又不是桌面的最顶层次未最小化的窗口最大化
|
||||
|
||||
if (c->isResizable()) {
|
||||
isTopWindowMaximized = true;
|
||||
} else {
|
||||
// 如果是固定大小的窗口,需要将窗口放到屏幕的正中间
|
||||
Placement::self()->placeCentered(c, workspace()->activeOutput()->geometry());
|
||||
c->updateGeometryRestore();
|
||||
isTopWindowMaximized = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qDebug() << "SingleWindowManager::switchTablet, minimize() caption:" << c->caption();
|
||||
c->minimize(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isTopWindowMaximized && m_bTabletMode) {
|
||||
showBackground();
|
||||
} else {
|
||||
hideBackground();
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void SingleWindowManager::addTransient(QVector<T*> &clients, T *transientClient)
|
||||
{
|
||||
clients.append(transientClient);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool SingleWindowManager::removeTransient(QVector<T*> &clients, T *transientClient)
|
||||
{
|
||||
const int remove = clients.indexOf(transientClient);
|
||||
if (remove == -1) {
|
||||
return false;
|
||||
}
|
||||
clients.removeAt(remove);
|
||||
return true;
|
||||
}
|
||||
|
||||
void SingleWindowManager::updateDesktopVisibleState(AbstractClient *desktop)
|
||||
{
|
||||
if (!desktop || !desktop->isDesktop()) {
|
||||
return;
|
||||
}
|
||||
if (desktop->caption().contains(QStringLiteral("ukui-tablet-desktop"))) {
|
||||
m_tabletDesktop = desktop;
|
||||
if (effects) {
|
||||
EffectsHandlerImpl *effect = static_cast<EffectsHandlerImpl *>(effects);
|
||||
bool isLoad = effect->isEffectLoaded(SCALEDESKTOP_EFFECT_NAME);
|
||||
// 如果桌面缩放特效加载了,则有特效去处理桌面的显示与隐藏
|
||||
if (isLoad)
|
||||
return;
|
||||
}
|
||||
qDebug() << __func__ << __LINE__ << "KWin::effects pointer is not initialized ! ! !" << m_bTabletMode;
|
||||
// 桌面缩放特效未加载,由 SingleWindowManager 管理桌面的显示与隐藏
|
||||
if (!m_bTabletMode) {
|
||||
m_tabletDesktop->hideClient();
|
||||
} else {
|
||||
m_tabletDesktop->showClient();
|
||||
}
|
||||
} else {
|
||||
m_pcDesktop = desktop;
|
||||
if (effects) {
|
||||
EffectsHandlerImpl *effect = static_cast<EffectsHandlerImpl *>(effects);
|
||||
bool isLoad = effect->isEffectLoaded(SCALEDESKTOP_EFFECT_NAME);
|
||||
// 如果桌面缩放特效加载了,则有特效去处理桌面的显示与隐藏
|
||||
if (isLoad)
|
||||
return;
|
||||
}
|
||||
qDebug() << __func__ << __LINE__ << "KWin::effects pointer is not initialized ! ! !" << m_bTabletMode;
|
||||
// 桌面缩放特效未加载,由 SingleWindowManager 管理桌面的显示与隐藏
|
||||
if (m_bTabletMode) {
|
||||
m_pcDesktop->hideClient();
|
||||
} else {
|
||||
m_pcDesktop->showClient();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SingleWindowManager::showBackground()
|
||||
{
|
||||
if(kwinApp()->operationMode() == Application::OperationMode::OperationModeX11) {
|
||||
if (m_blurHelperWindow) {
|
||||
m_blurHelperWindow->unminimize(true);
|
||||
}
|
||||
m_blurBackground->update();
|
||||
} else {
|
||||
m_blurBackground->show();
|
||||
// 对于 Internal window, 直接设置属性即可,没有必要去调用 KWindowEffects 的接口
|
||||
m_blurBackground->windowHandle()->setProperty("kwin_blur", QRegion());
|
||||
}
|
||||
}
|
||||
|
||||
void SingleWindowManager::hideBackground()
|
||||
{
|
||||
#ifndef QT_NO_DEBUG
|
||||
qDebug() << __func__ << "Hide Background ! ! !";
|
||||
#endif
|
||||
if(kwinApp()->operationMode() == Application::OperationMode::OperationModeX11) {
|
||||
if (m_blurHelperWindow) {
|
||||
m_blurHelperWindow->minimize(true);
|
||||
}
|
||||
} else {
|
||||
m_blurBackground->hide();
|
||||
}
|
||||
}
|
||||
|
||||
void SingleWindowManager::handleClientAdded(AbstractClient *client)
|
||||
{
|
||||
if (!client) {
|
||||
return;
|
||||
}
|
||||
// 存在部分窗口,它的主界面窗口还没有 show 出来或者隐藏了,找不到主界面窗口指针,但是该窗口仍为瞬态窗口,这
|
||||
// 种窗口我们暂时不将其加到瞬态窗口列表里。
|
||||
if (client->isTransient() && client->mainClients().size() > 0) {
|
||||
addTransient(m_transientClients, client);
|
||||
}
|
||||
if (TabletManager::self()->existTabletDesktop() && client->isDesktop()) {
|
||||
if (client->caption().contains(QStringLiteral("ukui-tablet-desktop"))) {
|
||||
qDebug() << __func__ << __LINE__ << "ukui-tablet-desktop add" << m_bTabletMode;
|
||||
m_tabletDesktop = client;
|
||||
if (!m_bTabletMode) {
|
||||
m_tabletDesktop->hideClient();
|
||||
}
|
||||
} else {
|
||||
qDebug() << __func__ << __LINE__ << "peony-qt-desktop add" << m_bTabletMode;
|
||||
m_pcDesktop = client;
|
||||
if (m_bTabletMode) {
|
||||
m_pcDesktop->hideClient();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!m_bTabletMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef QT_NO_DEBUG
|
||||
qDebug() << __func__ << client->caption();
|
||||
#endif
|
||||
}
|
||||
|
||||
void SingleWindowManager::handleClientRemoved(AbstractClient *client)
|
||||
{
|
||||
if (!client) {
|
||||
return;
|
||||
}
|
||||
bool isTransientRemoved = removeTransient(m_transientClients, client);
|
||||
if (!m_bTabletMode) {
|
||||
return;
|
||||
}
|
||||
#ifndef QT_NO_DEBUG
|
||||
qDebug() << __func__ << client->caption();
|
||||
#endif
|
||||
// 该窗口存在主界面窗口,移除此窗口后还有主界面窗口,直接return即可,不需要处理。但是 client->isTransient() 返回的值永远都
|
||||
// 是 false,因为 workspace 在发送 clientRemoved 信号前,已经将父子窗口全部清空关系了。所以要将瞬态窗口提前保存下来,利用自
|
||||
// 定义的 removeTransient() 函数来判断是否移除的是瞬态窗口。瞬态窗口不直接return的话可能会导致毛玻璃背景先隐藏再被显示出来。
|
||||
// wayland 环境下任务栏隐藏也会触发此槽函数,直接return即可。
|
||||
if (isTransientRemoved || client->isDock() || client->caption().contains(QStringLiteral("sidebar"))) {
|
||||
return;
|
||||
}
|
||||
else {
|
||||
// 窗口可以最大化,意味着毛玻璃背景窗口并没有显示出来
|
||||
if (client->isMaximizable()) {
|
||||
return;
|
||||
} else {
|
||||
// 窗口不能最大化,意味着毛玻璃背景显示出来了。所以关闭窗口时要隐藏毛玻璃背景窗口。
|
||||
qDebug() << __func__ << "Hide Background ! ! !";
|
||||
hideBackground();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SingleWindowManager::handleClientActivated(AbstractClient *client)
|
||||
{
|
||||
if (!m_bTabletMode || !client || client->caption() == QStringLiteral("tablet-taskbar")) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef QT_NO_DEBUG
|
||||
// transientFor() 拿到的返回值是不准确的, mainClients() 可以拿到所有的父窗口
|
||||
// 先不考虑 mainClients() 返回多个父窗口的情况,因为目前不确定是否会存在这种情况
|
||||
qDebug() << __func__ << "Caption: " << client->caption() << "WindowType: " << client->windowType()
|
||||
<< "resourceName: " << client->resourceName() << "resourceClass: " << client->resourceClass()
|
||||
<< "isDialog: " << client->isDialog() << "isUtility: " << client->isUtility()
|
||||
<< "isMaximizable: " << client->isMaximizable() << "transientFor: " << client->transientFor()
|
||||
<< "transients:" << client->transients() << "mainClients: " << client->mainClients();
|
||||
#endif
|
||||
|
||||
if (client->isDesktop() || client->isDock() || client == m_blurHelperWindow
|
||||
/* || client->caption().contains(QStringLiteral("sidebar")) */) {
|
||||
hideBackground();
|
||||
return;
|
||||
}
|
||||
if (client->caption().contains(QStringLiteral("sidebar"))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 鉴权窗口,不需要对其他窗口进行任何处理
|
||||
QStringList authenticationAgents = {"polkit-ukui-authentication-agent-1"
|
||||
, "polkit-kde-authentication-agent-1"
|
||||
, "kylin-installer"};
|
||||
if (authenticationAgents.contains(client->resourceClass())) {
|
||||
qDebug() <<__func__ << client->resourceClass();
|
||||
Placement::self()->placeCentered(client, workspace()->activeOutput()->geometry());
|
||||
// 某些应用打开前必须鉴权,在显示鉴权窗口时,将毛玻璃背景显示出来。
|
||||
// 在应用内部操作时激活鉴权窗口时,显示出毛玻璃背景窗口也无可厚非。
|
||||
showBackground();
|
||||
return;
|
||||
}
|
||||
|
||||
bool hasMaximizedWindow = true;
|
||||
|
||||
if (client->isMaximizable()) {
|
||||
// 能最大化的窗口直接最大化
|
||||
client->maximize(MaximizeFull);
|
||||
} else {
|
||||
// utility 表示一个小的持久的实用程序窗口,例如调色板或工具箱,用户可能在工作时保持该窗口的打开状态,所以这种类型窗口也不应该被居中
|
||||
if (!m_ignorePlaceCenterList.contains(client->resourceClass()) && !client->isUtility()) {
|
||||
// 如果应用不能最大化,则居中显示
|
||||
Placement::self()->placeCentered(client, workspace()->activeOutput()->geometry());
|
||||
}
|
||||
// 继续寻找是否含有主界面窗口
|
||||
if (client->mainClients().size() > 0) {
|
||||
AbstractClient *mainInterfaceClient = client->mainClients().at(0);
|
||||
if (mainInterfaceClient->isMaximizable()) {
|
||||
// 设置主界面窗口最大化
|
||||
mainInterfaceClient->maximize(MaximizeFull);
|
||||
} else {
|
||||
if (!m_ignorePlaceCenterList.contains(client->resourceClass())) {
|
||||
// 如果主界面窗口也不能最大化,主界面窗口也需要居中
|
||||
Placement::self()->placeCentered(mainInterfaceClient, workspace()->activeOutput()->geometry());
|
||||
}
|
||||
hasMaximizedWindow = false;
|
||||
}
|
||||
// 如果主界面窗口之前被最小化过,则需要单独再取消最小化,否则只会显示子窗口
|
||||
if (mainInterfaceClient->isMinimized()) {
|
||||
mainInterfaceClient->unminimize(true);
|
||||
}
|
||||
} else {
|
||||
// 没有主界面窗口,则代表只有一个不能最大化的应用
|
||||
hasMaximizedWindow = false;
|
||||
}
|
||||
}
|
||||
|
||||
makeOtherWindowMinimized(client->mainClients().size() > 0 ? client->mainClients().at(0) : client);
|
||||
if (hasMaximizedWindow) {
|
||||
qDebug() << __func__ << "Hide Background !!!";
|
||||
hideBackground();
|
||||
} else {
|
||||
qDebug() << __func__ << "Show Background !!!";
|
||||
showBackground();
|
||||
}
|
||||
}
|
||||
|
||||
void SingleWindowManager::handleClientMinimizedChanged(AbstractClient *client)
|
||||
{
|
||||
if (!m_bTabletMode || !client || !client->isMinimized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef QT_NO_DEBUG
|
||||
qDebug() << __func__ << client->caption();
|
||||
#endif
|
||||
// 该窗口存在主界面窗口,最小化此窗口后还有主界面窗口,直接return即可,不需要处理。
|
||||
// 存在窗口的主界面窗口还没有 show 出来或者隐藏了,该窗口为瞬态窗口,但是找不到主界面窗口
|
||||
if ((client->isTransient() && client->mainClients().size() > 0) || client->isSpecialWindow() || client == m_blurHelperWindow) {
|
||||
return;
|
||||
}
|
||||
const auto stacking_order = workspace()->stackingOrder();
|
||||
if (stacking_order.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = stacking_order.count() - 1; i > -1; --i) {
|
||||
AbstractClient *c = qobject_cast<AbstractClient*>(stacking_order.at(i));
|
||||
if (!c || c->isSpecialWindow() || c->skipTaskbar() || c->skipSwitcher() || c->skipPager()
|
||||
|| c->caption().contains(QStringLiteral("sidebar"))) {
|
||||
continue;
|
||||
}
|
||||
if (c == client && !c->isResizable()) {
|
||||
hideBackground();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SingleWindowManager::handleScreenGeometryChanged()
|
||||
{
|
||||
if (!m_bTabletMode || !workspace()->activeClient()) {
|
||||
return;
|
||||
}
|
||||
AbstractClient *activeClient = workspace()->activeClient();
|
||||
if (activeClient->isDock() || activeClient->isDesktop()) {
|
||||
return;
|
||||
}
|
||||
qDebug() << __func__ << activeClient->caption();
|
||||
if (!activeClient->isMaximizable()) {
|
||||
Placement::self()->placeCentered(activeClient, workspace()->activeOutput()->geometry());
|
||||
activeClient->updateGeometryRestore();
|
||||
}
|
||||
if (activeClient->mainClients().size() > 0) {
|
||||
for (auto *c : activeClient->mainClients()) {
|
||||
if (!c->isMaximizable()) {
|
||||
Placement::self()->placeCentered(c, workspace()->activeOutput()->geometry());
|
||||
// 屏幕输出大小改变时更新一下还原状态的geometry是为了防止居中后,在updateClientArea()时又被移动到PC模式保存的位置(不再居中显示)
|
||||
c->updateGeometryRestore();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SingleWindowManager::makeOtherWindowMinimized(AbstractClient *activeClient)
|
||||
{
|
||||
#ifndef QT_NO_DEBUG
|
||||
qDebug() << __func__ << "Caption: " << activeClient->caption() << "WindowType: " << activeClient->windowType()
|
||||
<< "isModal: " << activeClient->isModal() << "isDialog: " << activeClient->isDialog();
|
||||
#endif
|
||||
|
||||
if (activeClient->isUtility() || activeClient->isSpecialWindow()
|
||||
|| activeClient->caption().contains(QStringLiteral("sogouImeService"))
|
||||
|| m_ignorePlaceCenterList.contains(activeClient->resourceClass())) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool has_transient_client = (activeClient->transients().size() > 0 ? true : false);
|
||||
for (Toplevel *client : workspace()->stackingOrder()) {
|
||||
AbstractClient *c = qobject_cast<AbstractClient*>(client);
|
||||
if (!c) {
|
||||
continue;
|
||||
}
|
||||
bool isIgnoreWindow = (c->isDock() || c->isDesktop() || c->caption() == QStringLiteral("tablet-taskbar"));
|
||||
if (isIgnoreWindow) {
|
||||
continue;
|
||||
}
|
||||
if (c == activeClient) {
|
||||
// 如果窗口有瞬态窗口,也一并拉回上层
|
||||
if (c->transients().size()) {
|
||||
for (auto it = c->transients().constBegin(); it != c->transients().constEnd(); ++it) {
|
||||
(*it)->unminimize(true);
|
||||
// utility 表示一个小的持久的实用程序窗口,例如调色板或工具箱,用户可能在工作时保持该窗口的打开状态,所以这种类型窗口也不应该被居中
|
||||
if (!(*it)->isMaximizable() && !(*it)->isUtility()) {
|
||||
Placement::self()->placeCentered(*it, workspace()->activeOutput()->geometry());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!has_transient_client) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 如果激活的窗口存在瞬态窗口,需要将主界面窗口和瞬态窗口之间的其他应用的窗口最小化(存在这种可能性)。
|
||||
else if (has_transient_client && activeClient->transients().contains(c)) {
|
||||
break;
|
||||
}
|
||||
else if (!c->isMinimized())
|
||||
{
|
||||
qDebug() << __func__ << "exec minimize" << c->caption();
|
||||
c->minimize(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2022 KylinSoft Co., Ltd.
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef KWIN_TABLET_BACKGROUND_H
|
||||
#define KWIN_TABLET_BACKGROUND_H
|
||||
|
||||
#include <kwin_export.h>
|
||||
#include <config-kwin.h>
|
||||
#include <kwinglobals.h>
|
||||
#include <QVector>
|
||||
#include <QWidget>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
class AbstractClient;
|
||||
class EffectsHandlerImpl;
|
||||
class AbstractEffectLoader;
|
||||
|
||||
class KWIN_EXPORT TabletBackground : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
TabletBackground();
|
||||
~TabletBackground() override;
|
||||
|
||||
void init();
|
||||
void autoHide(bool on);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
private Q_SLOTS:
|
||||
void slotGeometryChanged();
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
class KWIN_EXPORT SingleWindowManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SingleWindowManager(QObject *parent = nullptr);
|
||||
~SingleWindowManager() override;
|
||||
void setBlurBackground(TabletBackground *blurBackground);
|
||||
void switchTablet(bool bTabletMode);
|
||||
void showBackground();
|
||||
void hideBackground();
|
||||
|
||||
private Q_SLOTS:
|
||||
void handleClientAdded(AbstractClient *client);
|
||||
void handleClientRemoved(AbstractClient *client);
|
||||
void handleClientActivated(AbstractClient *client);
|
||||
void handleClientMinimizedChanged(AbstractClient *client);
|
||||
void handleScreenGeometryChanged();
|
||||
|
||||
private:
|
||||
template <class T>
|
||||
void addTransient(QVector<T*> &clients, T *transientClient);
|
||||
template <class T>
|
||||
bool removeTransient(QVector<T*> &clients, T *transientClient);
|
||||
void updateDesktopVisibleState(AbstractClient *desktop);
|
||||
/**
|
||||
* @brief 将 activeClient 窗口下层的所有窗口最小化
|
||||
*
|
||||
* @param activeClient 该参数不能为瞬态窗口,必须为瞬态窗口的主界面窗口
|
||||
*/
|
||||
void makeOtherWindowMinimized(AbstractClient *activeClient);
|
||||
|
||||
private:
|
||||
AbstractClient *m_blurHelperWindow;
|
||||
TabletBackground *m_blurBackground;
|
||||
AbstractClient *m_pcDesktop;
|
||||
AbstractClient *m_tabletDesktop;
|
||||
QStringList m_ignorePlaceCenterList;
|
||||
bool m_bTabletMode;
|
||||
QVector<AbstractClient *> m_transientClients;
|
||||
};
|
||||
|
||||
class KWIN_EXPORT TabletManager: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~TabletManager() override;
|
||||
|
||||
void toggleTabletMode();
|
||||
bool tabletMode() { return m_bTabletMode; }
|
||||
bool existTabletDesktop() { return m_existTabletDesktop; }
|
||||
void setBlurBehind(double radius = 4000);
|
||||
void showBackground(double radius = 4000);
|
||||
// 外部接口,隐藏时设置为4000,使平板模式下的毛玻璃足够模糊
|
||||
void hideBackground(double radius = 4000);
|
||||
|
||||
private Q_SLOTS:
|
||||
void init();
|
||||
void slotSwitchTabletMode(bool bSurfaceMode);
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* @brief This signal is emitted when the mode of system has changed.
|
||||
*
|
||||
* @param bTabletMode
|
||||
*/
|
||||
void tabletModeChanged(bool bTabletMode);
|
||||
|
||||
private:
|
||||
void moveWindowBetweenVDesktop(QUuid windowId, int srcDesktopIndex, int destDesktopIndex);
|
||||
|
||||
private:
|
||||
TabletBackground* m_background;
|
||||
SingleWindowManager* m_singleWinManager;
|
||||
bool m_bTabletMode;
|
||||
bool m_existTabletDesktop;
|
||||
QMap<QUuid, int> m_windowDesktopMap;
|
||||
EffectsHandlerImpl *m_effects;
|
||||
AbstractEffectLoader *m_effectloader;
|
||||
KWIN_SINGLETON(TabletManager)
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1369,9 +1369,9 @@ void Workspace::slotWindowToPrevScreen()
|
|||
*/
|
||||
void Workspace::slotWindowMaximize()
|
||||
{
|
||||
if(m_bTabletMode)
|
||||
if(workspace()->isInTabletMode()) {
|
||||
return;
|
||||
|
||||
}
|
||||
if (USABLE_ACTIVE_CLIENT)
|
||||
performWindowOperation(active_client, Options::MaximizeOp);
|
||||
}
|
||||
|
@ -1501,11 +1501,7 @@ void Workspace::slotToggleShowDesktop()
|
|||
*/
|
||||
void Workspace::slotAlwaysShowDesktop()
|
||||
{
|
||||
if(isInTabletMode()) {
|
||||
active_client->minimize(false);
|
||||
} else {
|
||||
setShowingDesktop(true);
|
||||
}
|
||||
setShowingDesktop(true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
#include "main.h"
|
||||
#include "decorations/decorationbridge.h"
|
||||
#include "xwaylandclient.h"
|
||||
#include "tablet_manager.h"
|
||||
// KDE
|
||||
#include <KConfig>
|
||||
#include <KConfigGroup>
|
||||
|
@ -127,7 +128,6 @@ Workspace::Workspace()
|
|||
, set_active_client_recursion(0)
|
||||
, block_stacking_updates(0)
|
||||
, m_sessionManager(new SessionManager(this))
|
||||
, m_bTabletMode(false)
|
||||
{
|
||||
// If KWin was already running it saved its configuration after loosing the selection -> Reread
|
||||
QFuture<void> reparseConfigFuture = QtConcurrent::run(options, &Options::reparseConfiguration);
|
||||
|
@ -279,28 +279,6 @@ void Workspace::init()
|
|||
connect(server, &WaylandServer::shellClientRemoved, this, &Workspace::removeShellClient);
|
||||
}
|
||||
|
||||
//kwin启动时获取运行模式: 0:PC模式, 1:平板模式
|
||||
QDBusMessage message = QDBusMessage::createMethodCall("com.kylin.statusmanager.interface",
|
||||
"/",
|
||||
"com.kylin.statusmanager.interface",
|
||||
"get_current_tabletmode");
|
||||
|
||||
QDBusMessage response = QDBusConnection::sessionBus().call(message);
|
||||
|
||||
if (response.type() == QDBusMessage::ReplyMessage) {
|
||||
m_bTabletMode = response.arguments().takeFirst().toBool();
|
||||
slotSwitchTabletMode(m_bTabletMode);
|
||||
} else {
|
||||
printf("TabletMode qdus invalid\n");
|
||||
}
|
||||
//通过dbus监听PC-平板模式切换
|
||||
QDBusConnection::sessionBus().connect("com.kylin.statusmanager.interface",
|
||||
"/",
|
||||
"com.kylin.statusmanager.interface",
|
||||
"mode_change_signal",
|
||||
this,
|
||||
SLOT(slotSwitchTabletMode(bool)));
|
||||
|
||||
// SELI TODO: This won't work with unreasonable focus policies,
|
||||
// and maybe in rare cases also if the selected client doesn't
|
||||
// want focus
|
||||
|
@ -312,58 +290,6 @@ void Workspace::init()
|
|||
// TODO: ungrabXServer()
|
||||
}
|
||||
|
||||
void Workspace::slotSwitchTabletMode(bool bSurfaceMode)
|
||||
{
|
||||
if (m_bTabletMode == bSurfaceMode)
|
||||
return;
|
||||
m_bTabletMode = bSurfaceMode;
|
||||
switchTablet(m_bTabletMode);
|
||||
}
|
||||
|
||||
void Workspace::switchTablet(bool bOn)
|
||||
{
|
||||
bool bTopClientMaximize = true; //顶层窗口最大化标志
|
||||
for (int i = stacking_order.count() - 1; i > -1; --i) {
|
||||
AbstractClient *c = qobject_cast<AbstractClient*>(stacking_order.at(i));
|
||||
if (!c || c->isDock() || c->isDesktop() || c->caption().contains("sidebar", Qt::CaseInsensitive))
|
||||
continue;
|
||||
|
||||
//m_bTabletMode为true,表示pc切平板
|
||||
if (m_bTabletMode) {
|
||||
if (c->maximizeMode() == MaximizeRestore) {
|
||||
c->setTabletToPcRestoreFlag(true); //切平板前,如果是还原状态,则记录
|
||||
}
|
||||
|
||||
//并且该窗口不是最小化时
|
||||
if(!c->isMinimized()) {
|
||||
if(bTopClientMaximize) {
|
||||
bTopClientMaximize = false;
|
||||
c->maximize(MaximizeFull); //序号越大,越在顶层,只需要将既不是任务栏又不是桌面的最顶层次未最小化的窗口最大化
|
||||
|
||||
if (false == c->isResizable()) {
|
||||
if (!showingDesktop()) {
|
||||
// 如果是固定大小的窗口,需要将窗口放到屏幕的正中间
|
||||
Placement::self()->placeCentered(c, workspace()->activeOutput()->geometry());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
printf("Workspace::switchTablet, minimize unminimized caption:%s\n", c->caption().toStdString().c_str());
|
||||
c->minimize(true);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//m_bTabletMode为false,表示平板切pc,顶层最大化窗口如果之前是还原状态,则需还原
|
||||
if (MaximizeFull == c->maximizeMode() && true == bTopClientMaximize) {
|
||||
bTopClientMaximize = false;
|
||||
if (c->getTabletToPcRestoreFlag()) { //如果pc切平板前,记录的之前是还原状态,则当前激活窗口在切回pc后,需还原,否则,不需要处理
|
||||
c->maximize(MaximizeRestore);
|
||||
c->setTabletToPcRestoreFlag(false); //切回pc后,由于当前激活窗口已还原,则以后该窗口无需再做还原处理
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Workspace::initializeX11()
|
||||
{
|
||||
if (!kwinApp()->x11Connection()) {
|
||||
|
@ -731,9 +657,6 @@ X11Client *Workspace::createClient(xcb_window_t w, bool is_mapped)
|
|||
return nullptr;
|
||||
}
|
||||
addClient(c);
|
||||
|
||||
if(m_bTabletMode) //当是平板模式时,窗口默认最大化,其他窗口最小化/*,并且设置平板标签*/
|
||||
c->makeOthersMinimize();
|
||||
return c;
|
||||
}
|
||||
|
||||
|
@ -935,8 +858,13 @@ void Workspace::updateToolWindows(bool also_hide)
|
|||
{
|
||||
// TODO: What if Client's transiency/group changes? should this be called too? (I'm paranoid, am I not?)
|
||||
if (!options->isHideUtilityWindowsForInactive()) {
|
||||
for (auto it = m_x11Clients.constBegin(); it != m_x11Clients.constEnd(); ++it)
|
||||
for (auto it = m_x11Clients.constBegin(); it != m_x11Clients.constEnd(); ++it) {
|
||||
// 处于隐藏的窗口不应该被显示出来
|
||||
if ((*it)->isHiddenInternal()) {
|
||||
continue;
|
||||
}
|
||||
(*it)->showClient();
|
||||
}
|
||||
return;
|
||||
}
|
||||
const Group* group = nullptr;
|
||||
|
@ -1481,15 +1409,31 @@ void Workspace::setShowingDesktop(bool showing)
|
|||
} // ~StackingUpdatesBlocker
|
||||
|
||||
if (showing_desktop && topDesk) {
|
||||
requestFocus(topDesk);
|
||||
// 平板模式下,只需要把当前激活窗口最小化
|
||||
if (isInTabletMode()) {
|
||||
AbstractClient *tmpActiveClient = activeClient();
|
||||
if (tmpActiveClient) {
|
||||
if (tmpActiveClient->transientFor()) {
|
||||
tmpActiveClient->transientFor()->minimize(false);
|
||||
}
|
||||
else if (tmpActiveClient->isDesktop() || tmpActiveClient->isDock())
|
||||
return;
|
||||
tmpActiveClient->minimize(false);
|
||||
}
|
||||
} else {
|
||||
requestFocus(topDesk);
|
||||
}
|
||||
} else if (!showing_desktop && changed) {
|
||||
const auto client = FocusChain::self()->getForActivation(VirtualDesktopManager::self()->currentDesktop());
|
||||
if (client) {
|
||||
activateClient(client);
|
||||
if (!isInTabletMode()) {
|
||||
const auto client = FocusChain::self()->getForActivation(VirtualDesktopManager::self()->currentDesktop());
|
||||
if (client) {
|
||||
activateClient(client);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (changed)
|
||||
if (changed && !isInTabletMode()) {
|
||||
Q_EMIT showingDesktopChanged(showing);
|
||||
}
|
||||
}
|
||||
|
||||
void Workspace::disableGlobalShortcutsForClient(bool disable)
|
||||
|
@ -2016,6 +1960,11 @@ void Workspace::removeInternalClient(InternalClient *client)
|
|||
Q_EMIT internalClientRemoved(client);
|
||||
}
|
||||
|
||||
bool Workspace::isInTabletMode()
|
||||
{
|
||||
return TabletManager::self() ? TabletManager::self()->tabletMode() : false;
|
||||
}
|
||||
|
||||
Group* Workspace::findGroup(xcb_window_t leader) const
|
||||
{
|
||||
Q_ASSERT(leader != XCB_WINDOW_NONE);
|
||||
|
@ -2320,17 +2269,6 @@ void Workspace::updateClientArea()
|
|||
}
|
||||
}
|
||||
|
||||
//当屏幕旋转时,那些固定大小的窗口需要再次进行一次居中设置(除了任务栏和桌面)
|
||||
if (m_bTabletMode) {
|
||||
for (auto it = m_x11Clients.constBegin(); it != m_x11Clients.constEnd(); ++it) {
|
||||
if (true == (*it)->isResizable() || true == (*it)->isDock() || true == (*it)->isDesktop()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Placement::self()->placeCentered(*it, workspace()->activeOutput()->geometry());
|
||||
}
|
||||
}
|
||||
|
||||
if (m_workAreas != workAreas || m_restrictedAreas != restrictedAreas || m_screenAreas != screenAreas) {
|
||||
m_workAreas = workAreas;
|
||||
m_screenAreas = screenAreas;
|
||||
|
|
|
@ -416,8 +416,7 @@ public:
|
|||
*/
|
||||
void removeInternalClient(InternalClient *client);
|
||||
|
||||
bool isInTabletMode() {return m_bTabletMode;}
|
||||
void switchTablet(bool bOn);
|
||||
bool isInTabletMode();
|
||||
|
||||
public Q_SLOTS:
|
||||
void performWindowOperation(KWin::AbstractClient* c, Options::WindowOperation op);
|
||||
|
@ -436,8 +435,6 @@ public Q_SLOTS:
|
|||
void slotAlwaysShowDesktop();
|
||||
void slotAlwaysRestoreDesktop();
|
||||
|
||||
void slotSwitchTabletMode(bool bSurfaceMode);
|
||||
|
||||
void slotWindowMaximize();
|
||||
void slotWindowMaximizeVertical();
|
||||
void slotWindowMaximizeHorizontal();
|
||||
|
@ -669,7 +666,6 @@ private:
|
|||
static Workspace* _self;
|
||||
|
||||
bool workspaceInit;
|
||||
bool m_bTabletMode;
|
||||
|
||||
QScopedPointer<KStartupInfo> m_startup;
|
||||
QScopedPointer<ColorMapper> m_colorMapper;
|
||||
|
|
|
@ -1770,24 +1770,41 @@ void X11Client::closeWindow()
|
|||
if (!isCloseable())
|
||||
return;
|
||||
|
||||
bool doClose = true;
|
||||
// doClose default to true,
|
||||
// because there is no need to call AppManager on PC mode.
|
||||
if (workspace()->isInTabletMode()) {
|
||||
doClose = false;
|
||||
QDBusMessage message = QDBusMessage::createMethodCall("com.kylin.AppManager",
|
||||
"/com/kylin/AppManager",
|
||||
"com.kylin.AppManager",
|
||||
"ActiveProcessByWid");
|
||||
QList<QVariant> args;
|
||||
args.append(this->window());
|
||||
message.setArguments(args);
|
||||
QDBusMessage response = QDBusConnection::sessionBus().call(message);
|
||||
|
||||
if (response.type() == QDBusMessage::ReplyMessage) {
|
||||
doClose = response.arguments().takeFirst().toBool();
|
||||
qDebug() << "[DEBUG]: AppManager return " << doClose;
|
||||
} else {
|
||||
qDebug() << "[DEBUG]: ActiveProcessByWid qdus invalid.";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Update user time, because the window may create a confirming dialog.
|
||||
updateUserTime();
|
||||
|
||||
QDBusMessage message = QDBusMessage::createMethodCall("com.kylin.AppManager",
|
||||
"/com/kylin/AppManager",
|
||||
"com.kylin.AppManager",
|
||||
"ActiveProcessByWid");
|
||||
QList<QVariant> args;
|
||||
args.append(this->window());
|
||||
message.setArguments(args);
|
||||
QDBusConnection::sessionBus().send(message);
|
||||
|
||||
if (info->supportsProtocol(NET::DeleteWindowProtocol)) {
|
||||
sendClientMessage(window(), atoms->wm_protocols, atoms->wm_delete_window);
|
||||
pingWindow();
|
||||
} else // Client will not react on wm_delete_window. We have not choice
|
||||
// but destroy his connection to the XServer.
|
||||
killWindow();
|
||||
if (doClose)
|
||||
{
|
||||
if (info->supportsProtocol(NET::DeleteWindowProtocol)) {
|
||||
sendClientMessage(window(), atoms->wm_protocols, atoms->wm_delete_window);
|
||||
pingWindow();
|
||||
} else // Client will not react on wm_delete_window. We have not choice
|
||||
// but destroy his connection to the XServer.
|
||||
killWindow();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1979,21 +1996,6 @@ bool X11Client::takeFocus()
|
|||
}
|
||||
workspace()->setShouldGetFocus(this);
|
||||
|
||||
//如果是平板模式,则其他所有窗口均最小化
|
||||
if (Workspace::self()->isInTabletMode()){
|
||||
// 平板模式下,当窗口获得焦点时,如果是固定大小的窗口(除了任务栏),需要将窗口放到屏幕的正中间
|
||||
if (false == this->isResizable() && false == isDock() && false == isDesktop()) {
|
||||
Placement::self()->placeCentered(this, workspace()->activeOutput()->geometry());
|
||||
}
|
||||
makeOthersMinimize();
|
||||
} else {
|
||||
//如果pc切平板前,该窗口是还原状态,平板切pc后的窗口激活时,需将该窗口从最大化切换还原
|
||||
if (getTabletToPcRestoreFlag()) {
|
||||
setTabletToPcRestoreFlag(false);
|
||||
this->maximize(MaximizeRestore);
|
||||
}
|
||||
}
|
||||
|
||||
bool breakShowingDesktop = !keepAbove();
|
||||
if (breakShowingDesktop) {
|
||||
const auto members = group()->members();
|
||||
|
|
|
@ -536,7 +536,6 @@ private:
|
|||
QRect m_lastClientGeometry;
|
||||
QScopedPointer<X11DecorationRenderer> m_decorationRenderer;
|
||||
|
||||
bool bUnMakeOthersMinimizeFlag; //不最小化其他窗体标志
|
||||
unsigned int m_specialFlags = 0;
|
||||
|
||||
};
|
||||
|
|
|
@ -826,17 +826,34 @@ void XdgToplevelClient::showOnScreenEdge()
|
|||
void XdgToplevelClient::closeWindow()
|
||||
{
|
||||
if (isCloseable()) {
|
||||
QDBusMessage message = QDBusMessage::createMethodCall("com.kylin.AppManager",
|
||||
"/com/kylin/AppManager",
|
||||
"com.kylin.AppManager",
|
||||
"ActiveProcessByWid");
|
||||
QList<QVariant> args;
|
||||
args.append(this->window());
|
||||
message.setArguments(args);
|
||||
QDBusConnection::sessionBus().send(message);
|
||||
bool doClose = true;
|
||||
// doClose default to true,
|
||||
// because there is no need to call AppManager on PC mode.
|
||||
if (workspace()->isInTabletMode()) {
|
||||
doClose = false;
|
||||
QDBusMessage message = QDBusMessage::createMethodCall("com.kylin.AppManager",
|
||||
"/com/kylin/AppManager",
|
||||
"com.kylin.AppManager",
|
||||
"ActiveProcessByWid");
|
||||
QList<QVariant> args;
|
||||
args.append(this->window());
|
||||
message.setArguments(args);
|
||||
QDBusMessage response = QDBusConnection::sessionBus().call(message);
|
||||
|
||||
sendPing(PingReason::CloseWindow);
|
||||
m_shellSurface->sendClose();
|
||||
if (response.type() == QDBusMessage::ReplyMessage) {
|
||||
doClose = response.arguments().takeFirst().toBool();
|
||||
qDebug() << "[DEBUG]: AppManager return " << doClose;
|
||||
} else {
|
||||
qDebug() << "[DEBUG]: ActiveProcessByWid qdus invalid.";
|
||||
return;
|
||||
}
|
||||
}
|
||||
// TODO: 暂时上面ActiveProcessByWid在wayland下无法使用,先全部允许关闭
|
||||
doClose = true;
|
||||
if (doClose) {
|
||||
sendPing(PingReason::CloseWindow);
|
||||
m_shellSurface->sendClose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1019,21 +1036,6 @@ bool XdgToplevelClient::takeFocus()
|
|||
setActive(true);
|
||||
}
|
||||
|
||||
//如果是平板模式,则其他所有窗口均最小化
|
||||
if (Workspace::self()->isInTabletMode()){
|
||||
// 平板模式下,当窗口获得焦点时,如果是固定大小的窗口(除了任务栏),需要将窗口放到屏幕的正中间
|
||||
if (false == this->isResizable() && false == isDock() && false == isDesktop()) {
|
||||
Placement::self()->placeCentered(this, workspace()->activeOutput()->geometry());
|
||||
}
|
||||
makeOthersMinimize();
|
||||
} else {
|
||||
//如果pc切平板前,该窗口是还原状态,平板切pc后的窗口激活时,需将该窗口从最大化切换还原
|
||||
if (getTabletToPcRestoreFlag()) {
|
||||
setTabletToPcRestoreFlag(false);
|
||||
this->maximize(MaximizeRestore);
|
||||
}
|
||||
}
|
||||
|
||||
if (!keepAbove() && !isOnScreenDisplay() && !belongsToDesktop()) {
|
||||
workspace()->setShowingDesktop(false);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue