fix: 修复拖动无打开窗口触发分屏后自动打开应用的问题

原来的逻辑为在应用没有打开窗口的时候,需要自动打开一个窗口然后来触发分屏的操作;
根据和产品详细讨论,现该逻辑改为:在应用没有打开窗口的时候,无需触发分屏

Log:
Influence: 从任务栏拖动一个没有打开窗口的应用,观察是否打开应用(正常情况下不会打开应用),释放鼠标,观察应用图标是否回到任务栏上
Bug: https://pms.uniontech.com/bug-view-154349.html
Change-Id: I6d07097a85912caf15ce63952d6b84225b3aeaad
This commit is contained in:
donghualin 2022-11-17 16:08:24 +08:00
parent ea75c2e00d
commit b3172ccc96
5 changed files with 40 additions and 226 deletions

View File

@ -451,51 +451,8 @@ void AppDragWidget::initWaylandEnv()
return;
// 由于在wayland环境下无法触发drop事件导致鼠标无法释放所以这里暂时用XEventMonitor的方式(具体原因待查)
Dock::Position position = qApp->property(PROP_POSITION).value<Dock::Position>();
XEventMonitor *extralEventInter = new XEventMonitor(xEventMonitorService, xEventMonitorPath, QDBusConnection::sessionBus());
QList<MonitRect> extralRectList;
QList<QScreen *> screens = DisplayManager::instance()->screens();
for (QScreen *screen : screens) {
MonitRect monitorRect;
QRect screenRect = screen->geometry();
screenRect.setSize(screenRect.size() * screen->devicePixelRatio());
switch (position) {
case Top: {
monitorRect.x1 = screenRect.x();
monitorRect.y1 = screenRect.y();
monitorRect.x2 = screenRect.x() + screenRect.width();
monitorRect.y2 = screenRect.y();
}
break;
case Bottom: {
monitorRect.x1 = screenRect.x();
monitorRect.y1 = screenRect.y() + screenRect.height();
monitorRect.x2 = screenRect.x() + screenRect.width();
monitorRect.y2 = screenRect.y() + screenRect.height();
}
break;
case Left: {
monitorRect.x1 = screenRect.x();
monitorRect.y1 = screenRect.y();
monitorRect.x2 = screenRect.x();
monitorRect.y2 = screenRect.y() + screenRect.height();
}
break;
case Right: {
monitorRect.x1 = screenRect.x() + screenRect.width();
monitorRect.y1 = screenRect.y();
monitorRect.x2 = screenRect.x() + screenRect.width();
monitorRect.y2 = screenRect.y() + screenRect.height();
}
break;
}
if (!extralRectList.contains(monitorRect))
extralRectList << monitorRect;
}
QString key = extralEventInter->RegisterAreas(extralRectList, 1 << 1);
QString key = extralEventInter->RegisterFullScreen();
connect(this, &AppDragWidget::destroyed, this, [ key, extralEventInter ] {
extralEventInter->UnregisterArea(key);
delete extralEventInter;

View File

@ -48,12 +48,9 @@ SplitWindowManager *ScreenSpliter_Wayland::m_splitManager = nullptr;
*/
ScreenSpliter_Wayland::ScreenSpliter_Wayland(AppItem *appItem, DockEntryInter *entryInter, QObject *parent)
: ScreenSpliter(appItem, entryInter, parent)
, m_checkedNotSupport(false)
{
if (!m_splitManager)
m_splitManager = new SplitWindowManager;
connect(m_splitManager, &SplitWindowManager::splitStateChange, this, &ScreenSpliter_Wayland::onSplitStateChange);
}
ScreenSpliter_Wayland::~ScreenSpliter_Wayland()
@ -62,12 +59,8 @@ ScreenSpliter_Wayland::~ScreenSpliter_Wayland()
void ScreenSpliter_Wayland::startSplit(const QRect &rect)
{
if (entryInter()->windowInfos().size() == 0) {
// 如果默认打开的子窗口的数量为0则无需操作同时记录标记在打开新的窗口的时候设置遮罩
m_splitRect = rect;
entryInter()->Activate(QX11Info::getTimestamp());
if (!suportSplitScreen())
return;
}
setMaskVisible(rect, true);
}
@ -92,84 +85,32 @@ void ScreenSpliter_Wayland::setMaskVisible(const QRect &rect, bool visible)
bool ScreenSpliter_Wayland::split(SplitDirection direction)
{
setMaskVisible(QRect(), false);
const QString windowUuid = splitUuid();
if (windowUuid.isEmpty())
return false;
// 如果当前不支持分屏则返回false
if (!suportSplitScreen())
return false;
WindowInfoMap windowInfos = entryInter()->windowInfos();
m_splitManager->requestSplitWindow(windowInfos.first().uuid.toStdString().c_str(), direction);
std::string sUuid = windowUuid.toStdString();
const char *uuid = sUuid.c_str();
m_splitManager->requestSplitWindow(uuid, direction);
return true;
}
QString ScreenSpliter_Wayland::splitUuid() const
{
#ifdef USE_AM
WindowInfoMap windowsInfo = entryInter()->windowInfos();
if (windowsInfo.isEmpty())
return QString();
const QString uuid = windowsInfo.values()[0].uuid;
if (windowSupportSplit(uuid))
return uuid;
#endif
return QString();
}
bool ScreenSpliter_Wayland::windowSupportSplit(const QString &uuid) const
{
return m_splitManager->canSplit(uuid);
}
QString ScreenSpliter_Wayland::firstWindowUuid() const
{
#ifdef USE_AM
WindowInfoMap winInfos = entryInter()->windowInfos();
if (winInfos.size() == 0)
return QString();
return winInfos.begin().value().uuid;
#else
return QString();
#endif
}
void ScreenSpliter_Wayland::onSplitStateChange(const char *uuid, int splitable)
{
#ifdef USE_AM
const QString windowUuid = firstWindowUuid();
qDebug() << "Split State Changed, window uuid:" << windowUuid << "split uuid:" << uuid << "split value:" << splitable;
if (QString(uuid) != windowUuid)
return;
if (m_splitRect.isEmpty())
return;
if (splitable > 0) {
setMaskVisible(m_splitRect, true);
} else {
// 如果不支持二分屏,则退出当前的窗体,且标记当前不支持二分屏,下次打开的时候不再进行打开窗口来检测
entryInter()->ForceQuit();
m_checkedNotSupport = true;
}
m_splitRect = QRect(0, 0, 0, 0);
#endif
}
bool ScreenSpliter_Wayland::suportSplitScreen()
{
// 如果之前检测过是否不支持分屏(m_checkedNotSupport默认为false如果不支持分屏m_checkedNotSupport就会变为true),则直接返回不支持分屏
if (m_checkedNotSupport)
return false;
// 判断所有打开的窗口列表,只要有一个窗口支持分屏,就认为它支持分屏
const WindowInfoMap &windowsInfo = entryInter()->windowInfos();
for (const WindowInfo &windowInfo : windowsInfo) {
if (windowSupportSplit(windowInfo.uuid))
return true;
}
// 如果存在未打开的窗口,就默认让其认为支持,后续会根据这个来打开一个新的窗口
if (entryInter()->windowInfos().size() == 0)
return true;
// 如果存在已经打开的窗口
m_checkedNotSupport = splitUuid().isEmpty();
return (!m_checkedNotSupport);
// 如果所有的窗口都不支持分屏,就认为它不支持分屏,包括没有打开窗口的情况
return false;
}
bool ScreenSpliter_Wayland::releaseSplit()
@ -201,17 +142,10 @@ SplitWindowManager::~SplitWindowManager()
bool SplitWindowManager::canSplit(const QString &uuid) const
{
if (!m_clientManagement)
return false;
const QVector <ClientManagement::WindowState> &clientWindowStates = m_clientManagement->getWindowStates();
qInfo() << "client window states count:" << clientWindowStates.size();
for (ClientManagement::WindowState windowState : clientWindowStates) {
qDebug() << "window uuid:" << uuid << "window state uuid:" << windowState.uuid
<< "active:" << windowState.isActive << "resource name:" << windowState.resourceName;
if (windowState.splitable > 0 && QString(windowState.uuid) == uuid)
const QVector <ClientManagement::WindowState> &windowStates = m_clientManagement->getWindowStates();
for (const ClientManagement::WindowState &winState : windowStates)
if (winState.uuid == uuid && winState.splitable > 0)
return true;
};
return false;
}
@ -245,7 +179,6 @@ void SplitWindowManager::onConnectionFinished()
Registry *registry = new Registry(this);
connect(registry, &Registry::clientManagementAnnounced, this, [ this, registry ](quint32 name, quint32 version) {
m_clientManagement = registry->createClientManagement(name, version, this);
connect(m_clientManagement, &ClientManagement::splitStateChange, this, &SplitWindowManager::splitStateChange);
});
registry->setEventQueue(eventQueue);
registry->create(m_connectionThreadObject);

View File

@ -63,17 +63,11 @@ public:
private:
void setMaskVisible(const QRect &rect, bool visible);
QString splitUuid() const;
bool windowSupportSplit(const QString &uuid) const;
QString firstWindowUuid() const;
private Q_SLOTS:
void onSplitStateChange(const char* uuid, int splitable);
private:
static SplitWindowManager *m_splitManager;
QRect m_splitRect;
bool m_checkedNotSupport;
};
class SplitWindowManager : public QObject
@ -89,9 +83,6 @@ protected:
bool canSplit(const QString &uuid) const;
void requestSplitWindow(const char *uuid, const ScreenSpliter::SplitDirection &direction);
Q_SIGNALS:
void splitStateChange(const char *, int);
private Q_SLOTS:
void onConnectionFinished();
@ -99,6 +90,7 @@ private:
ClientManagement *m_clientManagement;
QThread *m_connectionThread;
ConnectionThread *m_connectionThreadObject;
QMap<QString, int> m_splitWindowState;
};
#endif // SCREENSPLITER_WAYLAND_H

View File

@ -78,49 +78,35 @@ static QByteArray windowProperty(quint32 WId, xcb_atom_t propAtom, xcb_atom_t ty
ScreenSpliter_Xcb::ScreenSpliter_Xcb(AppItem *appItem, DockEntryInter *entryInter, QObject *parent)
: ScreenSpliter(appItem, entryInter, parent)
, m_isSplitCreateWindow(false)
{
connect(entryInter, &DockEntryInter::WindowInfosChanged,
this, &ScreenSpliter_Xcb::onUpdateWindowInfo, Qt::QueuedConnection);
}
void ScreenSpliter_Xcb::startSplit(const QRect &rect)
{
if (!openWindow()) {
m_effectRect = rect;
if (!suportSplitScreen())
return;
}
showSplitScreenEffect(rect, true);
}
bool ScreenSpliter_Xcb::split(ScreenSpliter::SplitDirection direction)
{
if (!openWindow())
if (!suportSplitScreen())
return false;
// 如果当前的应用不支持分屏,也无需分屏,检查分屏的时候至少需要一个窗口,因此这里写在打开窗口之后
quint32 WId = splittingWindowWId();
if (WId == 0) {
// 如果当前存在主动打开的窗口,那么就关闭当前主动打开的窗口
if (m_isSplitCreateWindow) {
entryInter()->ForceQuit();
m_isSplitCreateWindow = false;
}
return false;
}
quint32 WId = entryInter()->windowInfos().keys().first();
xcb_client_message_event_t xev;
xev.response_type = XCB_CLIENT_MESSAGE;
xev.type = internAtom("_DEEPIN_SPLIT_WINDOW", false);
xev.window = WId;
xev.format = 32;
xev.data.data32[0] = direction_x11(direction); // 1: 左分屏 2: 右分屏 5 左上 6 右上 9 左下 10 右下 15: 全屏
xev.data.data32[1] = 1; // 1 进入预览 0 不进入预览
xev.data.data32[0] = direction_x11(direction); // 1: 左分屏 2: 右分屏 5 左上 6 右上 9 左下 10 右下 15: 全屏
xev.data.data32[1] = 1; // 1 进入预览 0 不进入预览
xcb_send_event(QX11Info::connection(), false, QX11Info::appRootWindow(QX11Info::appScreen()),
SubstructureNotifyMask, (const char *)&xev);
xcb_flush(QX11Info::connection());
return true;
}
@ -140,31 +126,14 @@ uint32_t ScreenSpliter_Xcb::direction_x11(ScreenSpliter::SplitDirection directio
return directionMapping.value(direction, SPLITUNKNOW);
}
bool ScreenSpliter_Xcb::openWindow()
{
// 查看当前应用是否有打开的窗口,如果没有,则先打开一个窗口
const WindowInfoMap windowlist = entryInter()->windowInfos();
if (!windowlist.isEmpty())
return true;
if (!m_isSplitCreateWindow) {
// 如果当前没有打开窗口,且未执行打开操作
entryInter()->Activate(QX11Info::getTimestamp());
m_isSplitCreateWindow = true;
}
return false;
}
void ScreenSpliter_Xcb::showSplitScreenEffect(const QRect &rect, bool visible)
{
quint32 WId = splittingWindowWId();
if (WId == 0)
if (!suportSplitScreen())
return;
quint32 WId = entryInter()->windowInfos().keys().first();
// 触发分屏的效果
xcb_client_message_event_t xev;
xev.response_type = XCB_CLIENT_MESSAGE;
xev.type = internAtom("_DEEPIN_SPLIT_OUTLINE", false);
xev.window = WId;
@ -180,61 +149,32 @@ void ScreenSpliter_Xcb::showSplitScreenEffect(const QRect &rect, bool visible)
xcb_flush(QX11Info::connection());
}
void ScreenSpliter_Xcb::onUpdateWindowInfo(const WindowInfoMap &info)
{
// 如果打开的是第一个窗口,且这个打开的窗口是通过拖动二分屏的方式打开,且当前是结束拖拽
// 并且不支持分屏那么这个窗口就需要关闭
if (!appItem()->isDragging()) {
releaseSplit();
} else if (!m_effectRect.isEmpty() && info.size() > 0) {
// 只有当需要触发分屏效果的时候发现当前没有窗口则记录当前分屏的区域保存在m_effectRect中
// 在新增窗口的时候如果返现m_effectRect有值则重新触发分屏并且清空m_effectRect防止再次打开窗口的时候再次触发分屏效果
showSplitScreenEffect(m_effectRect, true);
m_effectRect.setRect(0, 0, 0, 0);
}
}
bool ScreenSpliter_Xcb::suportSplitScreen()
{
// 如果当前的窗口的数量为0则不知道它是否支持分屏则始终让其返回true,然后打开窗口,因为窗口打开后,
// 要过一段事件才能收到信号,等收到信号后才知道它是否支持分屏,在窗口显示后会根据当前是否请求过执行分屏操作
// 来决定是否执行分屏的操作
if (entryInter()->windowInfos().size() == 0)
return true;
// 判断所有的窗口,只要有一个窗口支持分屏,就认为它支持分屏
QList<quint32> winIds = entryInter()->windowInfos().keys();
for (const quint32 &winId : winIds) {
if (windowSupportSplit(winId))
return true;
}
return (splittingWindowWId() != 0);
return false;
}
bool ScreenSpliter_Xcb::releaseSplit()
{
showSplitScreenEffect(QRect(), false);
if (!m_isSplitCreateWindow)
return false;
if (!entryInter()->windowInfos().isEmpty() && splittingWindowWId() == 0) {
// 释放后,如果当前的窗口是通过验证是否支持二分屏的方式来新建的窗口(m_isSplitCreateWindow == true)
// 并且存在打开的窗口(也有可能不存在打开的窗口,打开的窗口最后才出来,时机上不好控制,所以这种情况
// 在updateWindowInfos函数里面做了处理并且打开的窗口不支持二分屏则此时关闭新打开的窗口
entryInter()->ForceQuit();
}
m_isSplitCreateWindow = false;
return true;
}
quint32 ScreenSpliter_Xcb::splittingWindowWId()
bool ScreenSpliter_Xcb::windowSupportSplit(quint32 winId)
{
WindowInfoMap windowsInfo = entryInter()->windowInfos();
if (windowsInfo.size() == 0)
return 0;
quint32 WId = windowsInfo.keys().first();
xcb_atom_t propAtom = internAtom("_DEEPIN_NET_SUPPORTED", true);
QByteArray data = windowProperty(WId, propAtom, XCB_ATOM_CARDINAL, 4);
QByteArray data = windowProperty(winId, propAtom, XCB_ATOM_CARDINAL, 4);
bool supported = false;
if (const char *cdata = data.constData())
supported = *(reinterpret_cast<const quint8 *>(cdata));
return supported ? WId : 0;
return supported;
}

View File

@ -39,17 +39,9 @@ public:
bool releaseSplit() override;
private:
quint32 splittingWindowWId();
uint32_t direction_x11(ScreenSpliter::SplitDirection direction);
void showSplitScreenEffect(const QRect &rect, bool visible);
bool openWindow();
private Q_SLOTS:
void onUpdateWindowInfo(const WindowInfoMap &info);
private:
bool m_isSplitCreateWindow;
QRect m_effectRect;
bool windowSupportSplit(quint32 winId);
};
#endif // SCREENSPLITER_XCB_H