mirror of
https://github.com/linuxdeepin/dde-dock.git
synced 2025-06-04 09:23:03 +00:00
fix: 修复拖动无打开窗口触发分屏后自动打开应用的问题
原来的逻辑为在应用没有打开窗口的时候,需要自动打开一个窗口然后来触发分屏的操作; 根据和产品详细讨论,现该逻辑改为:在应用没有打开窗口的时候,无需触发分屏 Log: Influence: 从任务栏拖动一个没有打开窗口的应用,观察是否打开应用(正常情况下不会打开应用),释放鼠标,观察应用图标是否回到任务栏上 Bug: https://pms.uniontech.com/bug-view-154349.html Change-Id: I6d07097a85912caf15ce63952d6b84225b3aeaad
This commit is contained in:
parent
ea75c2e00d
commit
b3172ccc96
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user