2023-02-16 13:51:55 +08:00
|
|
|
// Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd.
|
|
|
|
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
|
|
|
//
|
|
|
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
|
|
|
2022-08-12 08:13:00 +00:00
|
|
|
#include "screenspliter_xcb.h"
|
|
|
|
#include "appitem.h"
|
|
|
|
|
|
|
|
#include <QX11Info>
|
|
|
|
|
|
|
|
#include <X11/X.h>
|
|
|
|
#include <X11/Xlib.h>
|
|
|
|
#include <xcb/xproto.h>
|
|
|
|
|
|
|
|
#define LEFT 1
|
|
|
|
#define RIGHT 2
|
|
|
|
#define TOP 3
|
|
|
|
#define BOTTOM 4
|
|
|
|
#define LEFTTOP 5
|
|
|
|
#define RIGHTTOP 6
|
|
|
|
#define LEFTBOTTOM 9
|
|
|
|
#define RIGHTBOTTOM 10
|
|
|
|
#define SPLITUNKNOW 0
|
|
|
|
|
|
|
|
static xcb_atom_t internAtom(const char *name, bool only_if_exist)
|
|
|
|
{
|
|
|
|
if (!name || *name == 0)
|
|
|
|
return XCB_NONE;
|
|
|
|
|
|
|
|
xcb_connection_t *connection = QX11Info::connection();
|
|
|
|
xcb_intern_atom_cookie_t cookie = xcb_intern_atom(connection, only_if_exist, strlen(name), name);
|
|
|
|
xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(connection, cookie, 0);
|
|
|
|
if (!reply)
|
|
|
|
return XCB_NONE;
|
|
|
|
|
|
|
|
xcb_atom_t atom = reply->atom;
|
|
|
|
free(reply);
|
|
|
|
|
|
|
|
return atom;
|
|
|
|
}
|
|
|
|
|
|
|
|
static QByteArray windowProperty(quint32 WId, xcb_atom_t propAtom, xcb_atom_t typeAtom, quint32 len)
|
|
|
|
{
|
|
|
|
xcb_connection_t *conn = QX11Info::connection();
|
|
|
|
xcb_get_property_cookie_t cookie = xcb_get_property(conn, false, WId, propAtom, typeAtom, 0, len);
|
|
|
|
xcb_generic_error_t *err = nullptr;
|
|
|
|
xcb_get_property_reply_t *reply = xcb_get_property_reply(conn, cookie, &err);
|
|
|
|
|
|
|
|
QByteArray data;
|
|
|
|
if (reply != nullptr) {
|
|
|
|
int valueLen = xcb_get_property_value_length(reply);
|
|
|
|
const char *buf = static_cast<const char *>(xcb_get_property_value(reply));
|
|
|
|
data.append(buf, valueLen);
|
|
|
|
free(reply);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err != nullptr) {
|
|
|
|
free(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2023-06-07 14:11:50 +08:00
|
|
|
ScreenSpliter_Xcb::ScreenSpliter_Xcb(AppItem *appItem, QObject *parent)
|
|
|
|
: ScreenSpliter(appItem, parent)
|
2022-08-12 08:13:00 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScreenSpliter_Xcb::startSplit(const QRect &rect)
|
|
|
|
{
|
2022-11-17 16:08:24 +08:00
|
|
|
if (!suportSplitScreen())
|
2022-08-12 08:13:00 +00:00
|
|
|
return;
|
2022-11-17 16:08:24 +08:00
|
|
|
|
2022-08-12 08:13:00 +00:00
|
|
|
showSplitScreenEffect(rect, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ScreenSpliter_Xcb::split(ScreenSpliter::SplitDirection direction)
|
|
|
|
{
|
2022-11-17 16:08:24 +08:00
|
|
|
if (!suportSplitScreen())
|
2022-08-12 08:13:00 +00:00
|
|
|
return false;
|
|
|
|
|
2023-06-13 15:05:44 +08:00
|
|
|
quint32 WId = appItem()->windowsInfos().keys().first();
|
2022-08-12 08:13:00 +00:00
|
|
|
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;
|
2022-11-17 16:08:24 +08:00
|
|
|
xev.data.data32[0] = direction_x11(direction); // 1: 左分屏 2: 右分屏 5 左上 6 右上 9 左下 10 右下 15: 全屏
|
|
|
|
xev.data.data32[1] = 1; // 1 进入预览 0 不进入预览
|
2022-08-12 08:13:00 +00:00
|
|
|
|
|
|
|
xcb_send_event(QX11Info::connection(), false, QX11Info::appRootWindow(QX11Info::appScreen()),
|
|
|
|
SubstructureNotifyMask, (const char *)&xev);
|
|
|
|
xcb_flush(QX11Info::connection());
|
2022-11-17 16:08:24 +08:00
|
|
|
|
2022-08-12 08:13:00 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t ScreenSpliter_Xcb::direction_x11(ScreenSpliter::SplitDirection direction)
|
|
|
|
{
|
|
|
|
static QMap<ScreenSpliter::SplitDirection, int> directionMapping = {
|
|
|
|
{ ScreenSpliter::Left, LEFT },
|
|
|
|
{ ScreenSpliter::Right, RIGHT },
|
|
|
|
{ ScreenSpliter::Top, TOP },
|
|
|
|
{ ScreenSpliter::Bottom, TOP },
|
|
|
|
{ ScreenSpliter::LeftTop, LEFTTOP },
|
|
|
|
{ ScreenSpliter::RightTop, RIGHTTOP },
|
|
|
|
{ ScreenSpliter::LeftBottom, LEFTBOTTOM },
|
|
|
|
{ ScreenSpliter::RightBottom, RIGHTBOTTOM }
|
|
|
|
};
|
|
|
|
|
|
|
|
return directionMapping.value(direction, SPLITUNKNOW);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScreenSpliter_Xcb::showSplitScreenEffect(const QRect &rect, bool visible)
|
|
|
|
{
|
2022-11-17 16:08:24 +08:00
|
|
|
if (!suportSplitScreen())
|
2022-08-12 08:13:00 +00:00
|
|
|
return;
|
|
|
|
|
2023-06-13 15:05:44 +08:00
|
|
|
quint32 WId = appItem()->windowsInfos().keys().first();
|
2022-08-12 08:13:00 +00:00
|
|
|
// 触发分屏的效果
|
|
|
|
xcb_client_message_event_t xev;
|
|
|
|
xev.response_type = XCB_CLIENT_MESSAGE;
|
|
|
|
xev.type = internAtom("_DEEPIN_SPLIT_OUTLINE", false);
|
|
|
|
xev.window = WId;
|
|
|
|
xev.format = 32;
|
|
|
|
xev.data.data32[0] = visible ? 1 : 0; // 1: 显示 0: 取消
|
|
|
|
xev.data.data32[1] = rect.x(); // X坐标
|
|
|
|
xev.data.data32[2] = rect.y(); // Y坐标
|
|
|
|
xev.data.data32[3] = rect.width(); // width
|
|
|
|
xev.data.data32[4] = rect.height(); // height
|
|
|
|
|
|
|
|
xcb_send_event(QX11Info::connection(), false, QX11Info::appRootWindow(QX11Info::appScreen()),
|
|
|
|
SubstructureNotifyMask, (const char *)&xev);
|
|
|
|
xcb_flush(QX11Info::connection());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ScreenSpliter_Xcb::suportSplitScreen()
|
|
|
|
{
|
2022-11-17 16:08:24 +08:00
|
|
|
// 判断所有的窗口,只要有一个窗口支持分屏,就认为它支持分屏
|
2023-06-13 15:05:44 +08:00
|
|
|
QList<quint32> winIds = appItem()->windowsInfos().keys();
|
2022-11-17 16:08:24 +08:00
|
|
|
for (const quint32 &winId : winIds) {
|
|
|
|
if (windowSupportSplit(winId))
|
|
|
|
return true;
|
|
|
|
}
|
2022-08-12 08:13:00 +00:00
|
|
|
|
2022-11-17 16:08:24 +08:00
|
|
|
return false;
|
2022-08-12 08:13:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ScreenSpliter_Xcb::releaseSplit()
|
|
|
|
{
|
2022-10-27 07:03:28 +00:00
|
|
|
showSplitScreenEffect(QRect(), false);
|
2022-08-12 08:13:00 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-11-17 16:08:24 +08:00
|
|
|
bool ScreenSpliter_Xcb::windowSupportSplit(quint32 winId)
|
2022-08-12 08:13:00 +00:00
|
|
|
{
|
|
|
|
xcb_atom_t propAtom = internAtom("_DEEPIN_NET_SUPPORTED", true);
|
2022-11-17 16:08:24 +08:00
|
|
|
QByteArray data = windowProperty(winId, propAtom, XCB_ATOM_CARDINAL, 4);
|
2022-08-12 08:13:00 +00:00
|
|
|
|
|
|
|
bool supported = false;
|
|
|
|
if (const char *cdata = data.constData())
|
|
|
|
supported = *(reinterpret_cast<const quint8 *>(cdata));
|
|
|
|
|
2022-11-17 16:08:24 +08:00
|
|
|
return supported;
|
2022-08-12 08:13:00 +00:00
|
|
|
}
|