mirror of
https://github.com/linuxdeepin/dde-dock.git
synced 2025-06-02 15:45:21 +00:00
feat: 拖动任务栏图标实现分屏效果
拖动任务栏图标到屏幕中间,如果在左侧,显示左分屏效果,在右侧,显示右分屏效果 Log: 完成任务栏图标分屏效果的功能 Influence: 从任务栏拖动图标到屏幕上方,查看是否有分屏功能 Task: https://pms.uniontech.com/task-view-163465.html Change-Id: I1a7a33646edb6f55972b8e5fa2c5f39ce026fe8e
This commit is contained in:
parent
f938f66bb5
commit
9c1eb32e24
@ -6,6 +6,11 @@ configure_file(dde-dock.pc.in dde-dock.pc @ONLY)
|
||||
|
||||
project(dde-dock)
|
||||
|
||||
set(CMAKE_THREAD_LIBS_INIT "-lpthread")
|
||||
set(CMAKE_HAVE_THREADS_LIBRARY 1)
|
||||
set(CMAKE_USE_PTHREADS_INIT 1)
|
||||
set(CMAKE_PREFER_PTHREAD_FLAG ON)
|
||||
|
||||
#set(CMAKE_VERBOSE_MAKEFILE ON)
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
5
debian/control
vendored
5
debian/control
vendored
@ -26,7 +26,10 @@ Build-Depends: debhelper (>= 8.0.0),
|
||||
libgtest-dev,
|
||||
libgmock-dev,
|
||||
qttools5-dev,
|
||||
libxcursor-dev
|
||||
libxcursor-dev,
|
||||
libqt5waylandclient5-dev,
|
||||
qtwayland5-private-dev,
|
||||
libdwayland-dev
|
||||
Standards-Version: 3.9.8
|
||||
Homepage: http://www.deepin.org/
|
||||
|
||||
|
@ -5,8 +5,8 @@ set(BIN_NAME dde-dock)
|
||||
configure_file(environments.h.in environments.h @ONLY)
|
||||
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -fsanitize=address -O2")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fsanitize=address -O2")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -fsanitize=address -O0")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fsanitize=address -O0")
|
||||
endif()
|
||||
|
||||
# Sources files
|
||||
@ -19,6 +19,8 @@ find_package(Qt5Concurrent REQUIRED)
|
||||
find_package(Qt5X11Extras REQUIRED)
|
||||
find_package(Qt5DBus REQUIRED)
|
||||
find_package(Qt5Svg REQUIRED)
|
||||
find_package(Qt5WaylandClient REQUIRED)
|
||||
find_package(Qt5XkbCommonSupport REQUIRED)
|
||||
find_package(DtkWidget REQUIRED)
|
||||
find_package(DtkCMake REQUIRED)
|
||||
find_package(dbusmenu-qt5 REQUIRED)
|
||||
@ -28,6 +30,9 @@ pkg_check_modules(DFrameworkDBus REQUIRED dframeworkdbus)
|
||||
pkg_check_modules(QGSettings REQUIRED gsettings-qt)
|
||||
pkg_check_modules(DtkGUI REQUIRED dtkgui)
|
||||
|
||||
set(Wayland_INCLUDE_DIRS /usr/include/DWayland/Client)
|
||||
set(Wayland_LIBRARIES /usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}/libDWaylandClient.so)
|
||||
|
||||
# driver-manager
|
||||
add_executable(${BIN_NAME}
|
||||
${SRCS}
|
||||
@ -45,6 +50,10 @@ target_include_directories(${BIN_NAME} PUBLIC
|
||||
${DtkGUI_INCLUDE_DIRS}
|
||||
${Qt5Svg_INCLUDE_DIRS}
|
||||
${dbusmenu-qt5_INCLUDE_DIRS}
|
||||
${Wayland_INCLUDE_DIRS}
|
||||
${Qt5WaylandClient_INCLUDE_DIRS}
|
||||
${Qt5WaylandClient_PRIVATE_INCLUDE_DIRS}
|
||||
${Qt5XkbCommonSupport_PRIVATE_INCLUDE_DIRS}
|
||||
../interfaces
|
||||
../widgets
|
||||
accessible
|
||||
@ -54,6 +63,7 @@ target_include_directories(${BIN_NAME} PUBLIC
|
||||
item
|
||||
item/components
|
||||
model
|
||||
screenspliter
|
||||
util
|
||||
window
|
||||
window/components
|
||||
@ -82,6 +92,10 @@ target_link_libraries(${BIN_NAME} PRIVATE
|
||||
${QGSettings_LIBRARIES}
|
||||
${DtkGUI_LIBRARIES}
|
||||
${Qt5Svg_LIBRARIES}
|
||||
${Wayland_LIBRARIES}
|
||||
${Qt5Wayland_LIBRARIES}
|
||||
${Qt5WaylandClient_LIBRARIES}
|
||||
${Qt5XkbCommonSupport_LIBRARIES}
|
||||
-lpthread -lm
|
||||
)
|
||||
|
||||
|
@ -49,7 +49,7 @@ void registerWindowInfoMetaType()
|
||||
|
||||
QDebug operator<<(QDebug argument, const WindowInfo &info)
|
||||
{
|
||||
argument << '(' << info.title << ',' << info.attention << ')';
|
||||
argument << '(' << info.title << ',' << info.attention << info.uuid << ')';
|
||||
|
||||
return argument;
|
||||
}
|
||||
@ -57,7 +57,7 @@ QDebug operator<<(QDebug argument, const WindowInfo &info)
|
||||
QDBusArgument &operator<<(QDBusArgument &argument, const WindowInfo &info)
|
||||
{
|
||||
argument.beginStructure();
|
||||
argument << info.title << info.attention;
|
||||
argument << info.title << info.attention << info.uuid;
|
||||
argument.endStructure();
|
||||
|
||||
return argument;
|
||||
@ -66,7 +66,7 @@ QDBusArgument &operator<<(QDBusArgument &argument, const WindowInfo &info)
|
||||
const QDBusArgument &operator>>(const QDBusArgument &argument, WindowInfo &info)
|
||||
{
|
||||
argument.beginStructure();
|
||||
argument >> info.title >> info.attention;
|
||||
argument >> info.title >> info.attention >> info.uuid;
|
||||
argument.endStructure();
|
||||
|
||||
return argument;
|
||||
@ -74,14 +74,20 @@ const QDBusArgument &operator>>(const QDBusArgument &argument, WindowInfo &info)
|
||||
|
||||
bool WindowInfo::operator==(const WindowInfo &rhs) const
|
||||
{
|
||||
return attention == rhs.attention &&
|
||||
title == rhs.title;
|
||||
return (attention == rhs.attention &&
|
||||
title == rhs.title &&
|
||||
uuid == rhs.uuid);
|
||||
}
|
||||
|
||||
class EntryPrivate
|
||||
{
|
||||
public:
|
||||
EntryPrivate() = default;
|
||||
EntryPrivate()
|
||||
: CurrentWindow(0)
|
||||
, IsActive(false)
|
||||
, IsDocked(false)
|
||||
, mode(0)
|
||||
{}
|
||||
|
||||
// begin member variables
|
||||
uint CurrentWindow;
|
||||
|
@ -53,6 +53,7 @@ public:
|
||||
public:
|
||||
bool attention;
|
||||
QString title;
|
||||
QString uuid;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(WindowInfo)
|
||||
|
@ -69,6 +69,17 @@ QScreen *DisplayManager::screen(const QString &screenName) const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QScreen *DisplayManager::screenAt(const QPoint &pos) const
|
||||
{
|
||||
for (QScreen *screen : m_screens) {
|
||||
QRect screenGeometry = screen->geometry();
|
||||
if (screenGeometry.contains(pos))
|
||||
return screen;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DisplayManager::primary
|
||||
* @return 主屏幕名称
|
||||
|
@ -45,6 +45,7 @@ public:
|
||||
|
||||
QList<QScreen *> screens() const;
|
||||
QScreen *screen(const QString &screenName) const;
|
||||
QScreen *screenAt(const QPoint &pos) const;
|
||||
QString primary() const;
|
||||
int screenRawWidth() const;
|
||||
int screenRawHeight() const;
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "xcb_misc.h"
|
||||
#include "appswingeffectbuilder.h"
|
||||
#include "utils.h"
|
||||
#include "screenspliter.h"
|
||||
|
||||
#include <X11/X.h>
|
||||
#include <X11/Xlib.h>
|
||||
@ -70,6 +71,7 @@ AppItem::AppItem(const QGSettings *appSettings, const QGSettings *activeAppSetti
|
||||
, m_refershIconTimer(new QTimer(this))
|
||||
, m_themeType(DGuiApplicationHelper::instance()->themeType())
|
||||
, m_createMSecs(QDateTime::currentMSecsSinceEpoch())
|
||||
, m_screenSpliter(ScreenSpliterFactory::createScreenSpliter(this, m_itemEntryInter))
|
||||
{
|
||||
QHBoxLayout *centralLayout = new QHBoxLayout;
|
||||
centralLayout->setMargin(0);
|
||||
@ -103,7 +105,6 @@ AppItem::AppItem(const QGSettings *appSettings, const QGSettings *activeAppSetti
|
||||
connect(this, &AppItem::requestUpdateEntryGeometries, this, &AppItem::updateWindowIconGeometries);
|
||||
|
||||
updateWindowInfos(m_itemEntryInter->windowInfos());
|
||||
refreshIcon();
|
||||
|
||||
if (m_appSettings)
|
||||
connect(m_appSettings, &QGSettings::changed, this, &AppItem::onGSettingsChanged);
|
||||
@ -182,6 +183,31 @@ void AppItem::setDockInfo(Dock::Position dockPosition, const QRect &dockGeometry
|
||||
}
|
||||
}
|
||||
|
||||
void AppItem::setDraging(bool drag)
|
||||
{
|
||||
if (drag == isDragging())
|
||||
return;
|
||||
|
||||
DockItem::setDraging(drag);
|
||||
if (!drag)
|
||||
m_screenSpliter->releaseSplit();
|
||||
}
|
||||
|
||||
void AppItem::startSplit(const QRect &rect)
|
||||
{
|
||||
m_screenSpliter->startSplit(rect);
|
||||
}
|
||||
|
||||
bool AppItem::supportSplitWindow()
|
||||
{
|
||||
return m_screenSpliter->suportSplitScreen();
|
||||
}
|
||||
|
||||
bool AppItem::splitWindowOnScreen(ScreenSpliter::SplitDirection direction)
|
||||
{
|
||||
return m_screenSpliter->split(direction);
|
||||
}
|
||||
|
||||
QString AppItem::accessibleName()
|
||||
{
|
||||
return m_itemEntryInter->name();
|
||||
@ -636,7 +662,9 @@ void AppItem::refreshIcon()
|
||||
update();
|
||||
|
||||
return;
|
||||
} else if (m_retryTimes > 0) {
|
||||
}
|
||||
|
||||
if (m_retryTimes > 0) {
|
||||
// reset times
|
||||
m_retryTimes = 0;
|
||||
}
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include <DGuiApplicationHelper>
|
||||
|
||||
class QGSettings;
|
||||
class ScreenSpliter;
|
||||
|
||||
class AppItem : public DockItem
|
||||
{
|
||||
@ -52,7 +53,14 @@ public:
|
||||
void undock();
|
||||
QWidget *appDragWidget();
|
||||
void setDockInfo(Dock::Position dockPosition, const QRect &dockGeometry);
|
||||
void setDraging(bool drag) override;
|
||||
|
||||
void startSplit(const QRect &rect);
|
||||
bool supportSplitWindow();
|
||||
bool splitWindowOnScreen(ScreenSpliter::SplitDirection direction);
|
||||
#ifdef USE_AM
|
||||
int mode() const;
|
||||
#endif
|
||||
inline ItemType itemType() const override { return App; }
|
||||
QPixmap appIcon(){ return m_appIcon; }
|
||||
virtual QString accessibleName() override;
|
||||
@ -146,6 +154,8 @@ private:
|
||||
qint64 m_createMSecs;
|
||||
|
||||
static QPoint MousePressPos;
|
||||
|
||||
ScreenSpliter *m_screenSpliter;
|
||||
};
|
||||
|
||||
#endif // APPITEM_H
|
||||
|
@ -22,6 +22,15 @@
|
||||
#include "../appitem.h"
|
||||
#include "appdragwidget.h"
|
||||
#include "utils.h"
|
||||
#include "displaymanager.h"
|
||||
|
||||
#include <com_deepin_api_xeventmonitor.h>
|
||||
|
||||
#define SPLIT_NONE 0
|
||||
#define SPLIT_LEFT 1
|
||||
#define SPLIT_RIGHT 2
|
||||
|
||||
using XEventMonitor = ::com::deepin::api::XEventMonitor;
|
||||
|
||||
AppDragWidget::AppDragWidget(QWidget *parent)
|
||||
: QGraphicsView(parent)
|
||||
@ -34,16 +43,11 @@ AppDragWidget::AppDragWidget(QWidget *parent)
|
||||
, m_animGroup(new QParallelAnimationGroup(this))
|
||||
, m_goBackAnim(new QPropertyAnimation(this, "pos", this))
|
||||
, m_dockPosition(Dock::Position::Bottom)
|
||||
, m_removeTips(new TipsWidget(this))
|
||||
, m_popupWindow(new DockPopupWindow(nullptr))
|
||||
, m_distanceMultiple(Utils::SettingValue("com.deepin.dde.dock.distancemultiple", "/com/deepin/dde/dock/distancemultiple/", "distance-multiple", 1.5).toDouble())
|
||||
, m_item(nullptr)
|
||||
, m_dockScreen(nullptr)
|
||||
{
|
||||
m_removeTips->setText(tr("Remove"));
|
||||
m_removeTips->setObjectName("AppRemoveTips");
|
||||
m_removeTips->setVisible(false);
|
||||
m_removeTips->installEventFilter(this);
|
||||
|
||||
m_popupWindow->setShadowBlurRadius(20);
|
||||
m_popupWindow->setRadius(18);
|
||||
m_popupWindow->setShadowYOffset(2);
|
||||
@ -55,11 +59,13 @@ AppDragWidget::AppDragWidget(QWidget *parent)
|
||||
m_scene->addItem(m_object.get());
|
||||
setScene(m_scene);
|
||||
|
||||
setWindowFlags(Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint);
|
||||
setAttribute(Qt::WA_TranslucentBackground);
|
||||
if (Utils::IS_WAYLAND_DISPLAY) {
|
||||
setWindowFlags(Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint | Qt::Window);
|
||||
setWindowFlags(Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint | Qt::Window | Qt::FramelessWindowHint);
|
||||
setAttribute(Qt::WA_NativeWindow);
|
||||
initWaylandEnv();
|
||||
} else {
|
||||
setWindowFlags(Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint);
|
||||
}
|
||||
viewport()->setAutoFillBackground(false);
|
||||
setFrameShape(QFrame::NoFrame);
|
||||
@ -71,10 +77,20 @@ AppDragWidget::AppDragWidget(QWidget *parent)
|
||||
|
||||
initAnimations();
|
||||
|
||||
m_followMouseTimer->setInterval(16);
|
||||
connect(m_followMouseTimer, &QTimer::timeout, this, &AppDragWidget::onFollowMouse);
|
||||
m_followMouseTimer->start();
|
||||
QTimer::singleShot(0, this, &AppDragWidget::onFollowMouse);
|
||||
if (!Utils::IS_WAYLAND_DISPLAY) {
|
||||
m_followMouseTimer->setInterval(16);
|
||||
connect(m_followMouseTimer, &QTimer::timeout, this, &AppDragWidget::onFollowMouse);
|
||||
m_followMouseTimer->start();
|
||||
QTimer::singleShot(0, this, &AppDragWidget::onFollowMouse);
|
||||
}
|
||||
}
|
||||
|
||||
void AppDragWidget::execFinished()
|
||||
{
|
||||
if (!m_bDragDrop)
|
||||
return;
|
||||
|
||||
dropHandler(QCursor::pos());
|
||||
}
|
||||
|
||||
void AppDragWidget::mouseMoveEvent(QMouseEvent *event)
|
||||
@ -95,11 +111,11 @@ void AppDragWidget::dragEnterEvent(QDragEnterEvent *event)
|
||||
|
||||
void AppDragWidget::dragMoveEvent(QDragMoveEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
showRemoveTips();
|
||||
if (isRemoveItem() && m_bDragDrop) {
|
||||
emit requestRemoveItem();
|
||||
}
|
||||
if (Utils::IS_WAYLAND_DISPLAY)
|
||||
return QGraphicsView::dragMoveEvent(event);
|
||||
|
||||
if (m_bDragDrop)
|
||||
moveHandler(QCursor::pos());
|
||||
}
|
||||
|
||||
/**获取应用的左上角坐标
|
||||
@ -156,18 +172,32 @@ const QPoint AppDragWidget::popupMarkPoint(Dock::Position pos)
|
||||
|
||||
void AppDragWidget::dropEvent(QDropEvent *event)
|
||||
{
|
||||
if (Utils::IS_WAYLAND_DISPLAY)
|
||||
return dropEvent(event);
|
||||
|
||||
m_followMouseTimer->stop();
|
||||
dropHandler(QCursor::pos());
|
||||
}
|
||||
|
||||
void AppDragWidget::hideEvent(QHideEvent *event)
|
||||
{
|
||||
deleteLater();
|
||||
if (Utils::IS_WAYLAND_DISPLAY)
|
||||
QGraphicsView::hideEvent(event);
|
||||
}
|
||||
|
||||
void AppDragWidget::dropHandler(const QPoint &pos)
|
||||
{
|
||||
m_bDragDrop = false;
|
||||
|
||||
if (isRemoveAble(QCursor::pos())) {
|
||||
if (canSplitWindow(pos)) {
|
||||
if (DWindowManagerHelper::instance()->hasComposite()) {
|
||||
showRemoveAnimation();
|
||||
} else {
|
||||
hide();
|
||||
}
|
||||
AppItem *appItem = static_cast<AppItem *>((Utils::IS_WAYLAND_DISPLAY && m_item) ? m_item : event->source());
|
||||
appItem->undock();
|
||||
m_popupWindow->setVisible(false);
|
||||
Q_EMIT requestSplitWindow(splitPosition());
|
||||
} else {
|
||||
if (DWindowManagerHelper::instance()->hasComposite()) {
|
||||
showGoBackAnimation();
|
||||
@ -177,11 +207,26 @@ void AppDragWidget::dropEvent(QDropEvent *event)
|
||||
}
|
||||
}
|
||||
|
||||
void AppDragWidget::hideEvent(QHideEvent *event)
|
||||
void AppDragWidget::moveHandler(const QPoint &pos)
|
||||
{
|
||||
deleteLater();
|
||||
if (Utils::IS_WAYLAND_DISPLAY)
|
||||
QGraphicsView::hideEvent(event);
|
||||
if (canSplitWindow(pos)) {
|
||||
QRect screenGeometry = splitGeometry(pos);
|
||||
if (screenGeometry.isValid() && screenGeometry != m_lastMouseGeometry) {
|
||||
qDebug() << "change area:" << screenGeometry;
|
||||
Q_EMIT requestChangedArea(screenGeometry);
|
||||
m_lastMouseGeometry = screenGeometry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AppDragWidget::moveCurrent(const QPoint &destPos)
|
||||
{
|
||||
if (DWindowManagerHelper::instance()->hasComposite()) {
|
||||
move(destPos.x() - width() / 2, destPos.y() - height() / 2);
|
||||
} else {
|
||||
// 窗口特效未开启时会隐藏m_object绘制的图标,移动的图标为QDrag绘制的图标
|
||||
move(destPos.x(), destPos.y());
|
||||
}
|
||||
}
|
||||
|
||||
void AppDragWidget::setAppPixmap(const QPixmap &pix)
|
||||
@ -211,7 +256,7 @@ void AppDragWidget::setOriginPos(const QPoint position)
|
||||
|
||||
void AppDragWidget::setPixmapOpacity(qreal opacity)
|
||||
{
|
||||
if (isRemoveAble(QCursor::pos())) {
|
||||
if (canSplitWindow(QCursor::pos())) {
|
||||
m_object->setOpacity(opacity);
|
||||
m_animOpacity->setStartValue(opacity);
|
||||
} else {
|
||||
@ -220,34 +265,6 @@ void AppDragWidget::setPixmapOpacity(qreal opacity)
|
||||
}
|
||||
}
|
||||
|
||||
bool AppDragWidget::isRemoveable(const Position &dockPos, const QRect &doctRect)
|
||||
{
|
||||
const QPoint &p = QCursor::pos();
|
||||
switch (dockPos) {
|
||||
case Dock::Position::Left:
|
||||
if ((p.x() - doctRect.topRight().x()) > (doctRect.width() * 3)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case Dock::Position::Top:
|
||||
if ((p.y() - doctRect.bottomLeft().y()) > (doctRect.height() * 3)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case Dock::Position::Right:
|
||||
if ((doctRect.topLeft().x() - p.x()) > (doctRect.width() * 3)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case Dock::Position::Bottom:
|
||||
if ((doctRect.topLeft().y() - p.y()) > (doctRect.height() * 3)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AppDragWidget::initAnimations()
|
||||
{
|
||||
m_animScale->setDuration(300);
|
||||
@ -303,79 +320,212 @@ void AppDragWidget::onRemoveAnimationStateChanged(QAbstractAnimation::State newS
|
||||
}
|
||||
}
|
||||
|
||||
/**判断图标拖到一定高度(默认任务栏高度的1.5倍)后是否可以移除
|
||||
* @brief AppDragWidget::isRemoveAble
|
||||
* @param curPos 当前鼠标所在位置
|
||||
* @return 返回true可移除,false不可移除
|
||||
/** 判断应用区域图标是否被拖出任务栏
|
||||
* @brief AppDragWidget::canSplitWindow
|
||||
* @return 返回true应用移出任务栏,false应用在任务栏内
|
||||
*/
|
||||
bool AppDragWidget::isRemoveAble(const QPoint &curPos)
|
||||
bool AppDragWidget::canSplitWindow(const QPoint &pos) const
|
||||
{
|
||||
const QPoint &p = curPos;
|
||||
switch (m_dockPosition) {
|
||||
case Dock::Position::Left:
|
||||
if ((p.x() - m_dockGeometry.topRight().x()) > (m_dockGeometry.width() * m_distanceMultiple)) {
|
||||
if ((pos.x() > m_dockGeometry.topRight().x())) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case Dock::Position::Top:
|
||||
if ((p.y() - m_dockGeometry.bottomLeft().y()) > (m_dockGeometry.height() * m_distanceMultiple)) {
|
||||
if ((pos.y() > m_dockGeometry.bottomLeft().y())) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case Dock::Position::Right:
|
||||
if ((m_dockGeometry.topLeft().x() - p.x()) > (m_dockGeometry.width() * m_distanceMultiple)) {
|
||||
if ((m_dockGeometry.topLeft().x() > pos.x())) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case Dock::Position::Bottom:
|
||||
if ((m_dockGeometry.topLeft().y() - p.y()) > (m_dockGeometry.height() * m_distanceMultiple)) {
|
||||
if ((m_dockGeometry.topLeft().y() > pos.y())) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**判断应用区域图标是否被拖出任务栏
|
||||
* @brief AppDragWidget::isRemoveItem
|
||||
* @return 返回true应用移出任务栏,false应用在任务栏内
|
||||
/**
|
||||
* @brief AppDragWidget::splitPosition
|
||||
* @return 1 左分屏;2 右分屏;5 左上;6 右上;9 左下;10 右下;15全屏。这些值是窗管给的
|
||||
*/
|
||||
bool AppDragWidget::isRemoveItem()
|
||||
ScreenSpliter::SplitDirection AppDragWidget::splitPosition() const
|
||||
{
|
||||
const QPoint &p = QCursor::pos();
|
||||
QPoint pos = QCursor::pos();
|
||||
QScreen *currentScreen = DisplayManager::instance()->screenAt(pos);
|
||||
|
||||
if (!currentScreen)
|
||||
return ScreenSpliter::None;
|
||||
|
||||
int xCenter = currentScreen->geometry().x() + currentScreen->size().width() / 2;
|
||||
// 1表示左分屏
|
||||
if (pos.x() < xCenter)
|
||||
return ScreenSpliter::Left;
|
||||
|
||||
// 2表示右分屏
|
||||
if (pos.x() > xCenter)
|
||||
return ScreenSpliter::Right;
|
||||
|
||||
return ScreenSpliter::None;
|
||||
}
|
||||
|
||||
void AppDragWidget::adjustDesktopGeometry(QRect &rect) const
|
||||
{
|
||||
QRect rectGeometry = m_dockGeometry;
|
||||
rectGeometry.setWidth(rectGeometry.width() * qApp->devicePixelRatio());
|
||||
rectGeometry.setHeight(rectGeometry.height() * qApp->devicePixelRatio());
|
||||
switch (m_dockPosition) {
|
||||
case Dock::Position::Left:
|
||||
if ((p.x() > m_dockGeometry.topRight().x())) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case Dock::Position::Top:
|
||||
if ((p.y() > m_dockGeometry.bottomLeft().y())) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case Dock::Position::Right:
|
||||
if ((m_dockGeometry.topLeft().x() > p.x())) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case Dock::Position::Bottom:
|
||||
if ((m_dockGeometry.topLeft().y() > p.y())) {
|
||||
return true;
|
||||
case Dock::Position::Left: {
|
||||
int leftX = (rectGeometry.x() + rectGeometry.width()) * qApp->devicePixelRatio();
|
||||
if (rect.x() < leftX) {
|
||||
rect.setX(leftX);
|
||||
rect.setWidth(rect.width() - (leftX - rect.x()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
case Dock::Position::Top: {
|
||||
int topY = (rectGeometry.y() + rectGeometry.height()) * qApp->devicePixelRatio();
|
||||
if (rect.y() < topY) {
|
||||
rect.setY(topY);
|
||||
rect.setHeight(rect.height() - (topY - rect.y()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Dock::Position::Right: {
|
||||
int rightX = rectGeometry.x() * qApp->devicePixelRatio();
|
||||
if (rightX < rect.x() + rect.width() * qApp->devicePixelRatio())
|
||||
rect.setWidth(rect.width() - (rect.x() + rect.width() - rightX));
|
||||
break;
|
||||
}
|
||||
case Dock::Position::Bottom: {
|
||||
int bottomY = rectGeometry.y() * qApp->devicePixelRatio();
|
||||
if (bottomY < rect.y() + rect.height() * qApp->devicePixelRatio())
|
||||
rect.setHeight(rect.height() - (rect.y() + rect.height() - bottomY));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QRect AppDragWidget::splitGeometry(const QPoint &pos) const
|
||||
{
|
||||
QList<QScreen *> screens = DisplayManager::instance()->screens();
|
||||
for (QScreen *screen : screens) {
|
||||
QRect screenGeometry = screen->geometry();
|
||||
screenGeometry.setWidth(screenGeometry.width() * qApp->devicePixelRatio());
|
||||
screenGeometry.setHeight(screenGeometry.height() * qApp->devicePixelRatio());
|
||||
if (!screenGeometry.contains(pos))
|
||||
continue;
|
||||
|
||||
// 左右分屏即可
|
||||
int centerX = screenGeometry.x() + screenGeometry.width() / 2;
|
||||
if (pos.x() < centerX) {
|
||||
// 左分屏
|
||||
QRect rectLeft = screenGeometry;
|
||||
rectLeft.setWidth(screenGeometry.width() / 2);
|
||||
adjustDesktopGeometry(rectLeft);
|
||||
return rectLeft;
|
||||
}
|
||||
if (pos.x() > centerX) {
|
||||
// 右分屏
|
||||
QRect rectRight = screenGeometry;
|
||||
rectRight.setLeft(screenGeometry.x() + screenGeometry.width() / 2);
|
||||
rectRight.setWidth(screenGeometry.width() / 2);
|
||||
adjustDesktopGeometry(rectRight);
|
||||
return rectRight;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return QRect();
|
||||
}
|
||||
|
||||
void AppDragWidget::initWaylandEnv()
|
||||
{
|
||||
if (!Utils::IS_WAYLAND_DISPLAY)
|
||||
return;
|
||||
|
||||
// 由于在wayland环境下无法触发drop事件,导致鼠标无法释放,所以这里暂时用XEventMonitor的方式(具体原因待查)
|
||||
Dock::Position position = qApp->property(PROP_POSITION).value<Dock::Position>();
|
||||
XEventMonitor *extralEventInter = new XEventMonitor("com.deepin.api.XEventMonitor", "/com/deepin/api/XEventMonitor", 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);
|
||||
connect(this, &AppDragWidget::destroyed, this, [ key, extralEventInter ] {
|
||||
extralEventInter->UnregisterArea(key);
|
||||
delete extralEventInter;
|
||||
QDrag::cancel();
|
||||
});
|
||||
|
||||
connect(extralEventInter, &XEventMonitor::ButtonRelease, this, &AppDragWidget::onButtonRelease);
|
||||
connect(extralEventInter, &XEventMonitor::CursorMove,this, &AppDragWidget::onCursorMove);
|
||||
}
|
||||
|
||||
void AppDragWidget::onButtonRelease(int, int x, int y, const QString &)
|
||||
{
|
||||
if (!m_bDragDrop)
|
||||
return;
|
||||
|
||||
dropHandler(QPoint(x, y));
|
||||
|
||||
QDrag::cancel();
|
||||
}
|
||||
|
||||
void AppDragWidget::onCursorMove(int x, int y, const QString &)
|
||||
{
|
||||
QPoint pos = QPoint(x, y);
|
||||
moveCurrent(pos);
|
||||
moveHandler(pos);
|
||||
}
|
||||
|
||||
void AppDragWidget::onFollowMouse()
|
||||
{
|
||||
QPoint destPos = QCursor::pos();
|
||||
if (DWindowManagerHelper::instance()->hasComposite()) {
|
||||
move(destPos.x() - width() / 2, destPos.y() - height() / 2);
|
||||
} else {
|
||||
move(destPos.x(), destPos.y()); // 窗口特效未开启时会隐藏m_object绘制的图标,移动的图标为QDrag绘制的图标
|
||||
}
|
||||
moveCurrent(QCursor::pos());
|
||||
}
|
||||
|
||||
void AppDragWidget::enterEvent(QEvent *event)
|
||||
@ -388,50 +538,6 @@ void AppDragWidget::enterEvent(QEvent *event)
|
||||
}
|
||||
}
|
||||
|
||||
/**显示移除应用提示窗口
|
||||
* @brief AppDragWidget::showRemoveTips
|
||||
*/
|
||||
void AppDragWidget::showRemoveTips()
|
||||
{
|
||||
Dock::Position pos = Dock::Position::Bottom;
|
||||
|
||||
DockPopupWindow *popup = m_popupWindow.data();
|
||||
if (isRemoveAble(QCursor::pos())) {
|
||||
QWidget *lastContent = popup->getContent();
|
||||
if (lastContent)
|
||||
lastContent->setVisible(false);
|
||||
|
||||
switch (pos) {
|
||||
case Top: popup->setArrowDirection(DockPopupWindow::ArrowTop); break;
|
||||
case Bottom: popup->setArrowDirection(DockPopupWindow::ArrowBottom); break;
|
||||
case Left: popup->setArrowDirection(DockPopupWindow::ArrowLeft); break;
|
||||
case Right: popup->setArrowDirection(DockPopupWindow::ArrowRight); break;
|
||||
}
|
||||
popup->resize(m_removeTips->sizeHint());
|
||||
popup->setContent(m_removeTips);
|
||||
|
||||
const QPoint p = popupMarkPoint(pos);
|
||||
if (!popup->isVisible())
|
||||
QMetaObject::invokeMethod(popup, "show", Qt::QueuedConnection, Q_ARG(QPoint, p), Q_ARG(bool, true));
|
||||
else
|
||||
popup->show(p, true);
|
||||
|
||||
m_object->setOpacity(0.5);
|
||||
m_animOpacity->setStartValue(0.5);
|
||||
} else {
|
||||
m_object->setOpacity(1.0);
|
||||
m_animOpacity->setStartValue(1.0);
|
||||
if (popup->isVisible())
|
||||
popup->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
void AppDragWidget::moveEvent(QMoveEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
showRemoveTips();
|
||||
}
|
||||
|
||||
QuickDragWidget::QuickDragWidget(QWidget *parent)
|
||||
: AppDragWidget(parent)
|
||||
{
|
||||
@ -471,3 +577,36 @@ void QuickDragWidget::dragMoveEvent(QDragMoveEvent *event)
|
||||
AppDragWidget::dragMoveEvent(event);
|
||||
requestDragMove(event);
|
||||
}
|
||||
|
||||
/**判断图标拖到一定高度(默认任务栏高度的1.5倍)后是否可以移除
|
||||
* @brief AppDragWidget::isRemoveAble
|
||||
* @param curPos 当前鼠标所在位置
|
||||
* @return 返回true可移除,false不可移除
|
||||
*/
|
||||
bool QuickDragWidget::isRemoveAble(const QPoint &curPos)
|
||||
{
|
||||
const QPoint &p = curPos;
|
||||
switch (m_dockPosition) {
|
||||
case Dock::Position::Left:
|
||||
if ((p.x() - m_dockGeometry.topRight().x()) > (m_dockGeometry.width() * m_distanceMultiple)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case Dock::Position::Top:
|
||||
if ((p.y() - m_dockGeometry.bottomLeft().y()) > (m_dockGeometry.height() * m_distanceMultiple)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case Dock::Position::Right:
|
||||
if ((m_dockGeometry.topLeft().x() - p.x()) > (m_dockGeometry.width() * m_distanceMultiple)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case Dock::Position::Bottom:
|
||||
if ((m_dockGeometry.topLeft().y() - p.y()) > (m_dockGeometry.height() * m_distanceMultiple)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -23,6 +23,8 @@
|
||||
#define APPDRAGWIDGET_H
|
||||
|
||||
#include "constants.h"
|
||||
#include "screenspliter.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <QPixmap>
|
||||
#include <QGraphicsObject>
|
||||
@ -38,6 +40,9 @@
|
||||
#include "dockpopupwindow.h"
|
||||
#include "dockitem.h"
|
||||
|
||||
class QDrag;
|
||||
class DockScreen;
|
||||
|
||||
class AppGraphicsObject : public QGraphicsObject
|
||||
{
|
||||
public:
|
||||
@ -85,18 +90,18 @@ class AppDragWidget : public QGraphicsView
|
||||
public:
|
||||
explicit AppDragWidget(QWidget *parent = Q_NULLPTR);
|
||||
|
||||
void execFinished();
|
||||
void setAppPixmap(const QPixmap &pix);
|
||||
void setDockInfo(Dock::Position dockPosition, const QRect &dockGeometry);
|
||||
void setOriginPos(const QPoint position);
|
||||
void setPixmapOpacity(qreal opacity);
|
||||
bool isRemoveAble(const QPoint &curPos);
|
||||
void setItem(DockItem *item) { m_item = item; }
|
||||
static bool isRemoveable(const Dock::Position &dockPos, const QRect &doctRect);
|
||||
void showRemoveAnimation();
|
||||
void showGoBackAnimation();
|
||||
|
||||
signals:
|
||||
void requestRemoveItem();
|
||||
void requestChangedArea(QRect);
|
||||
void requestSplitWindow(ScreenSpliter::SplitDirection);
|
||||
|
||||
protected:
|
||||
void mouseMoveEvent(QMouseEvent *event) override;
|
||||
@ -104,7 +109,6 @@ protected:
|
||||
void dragMoveEvent(QDragMoveEvent *event) override;
|
||||
void dropEvent(QDropEvent *event) override;
|
||||
void hideEvent(QHideEvent *event) override;
|
||||
void moveEvent(QMoveEvent *event) override;
|
||||
void enterEvent(QEvent *event) override;
|
||||
|
||||
private:
|
||||
@ -113,11 +117,20 @@ private:
|
||||
QAbstractAnimation::State oldState);
|
||||
const QPoint popupMarkPoint(Dock::Position pos);
|
||||
const QPoint topleftPoint() const;
|
||||
void showRemoveTips();
|
||||
bool isRemoveItem();
|
||||
bool canSplitWindow(const QPoint &pos) const;
|
||||
ScreenSpliter::SplitDirection splitPosition() const;
|
||||
QRect splitGeometry(const QPoint &pos) const;
|
||||
void initWaylandEnv();
|
||||
|
||||
void dropHandler(const QPoint &pos);
|
||||
void moveHandler(const QPoint &pos);
|
||||
void moveCurrent(const QPoint &destPos);
|
||||
void adjustDesktopGeometry(QRect &rect) const;
|
||||
|
||||
private Q_SLOTS:
|
||||
void onFollowMouse();
|
||||
void onButtonRelease(int, int x, int y, const QString &);
|
||||
void onCursorMove(int x, int y, const QString &);
|
||||
|
||||
protected:
|
||||
QScopedPointer<AppGraphicsObject> m_object;
|
||||
@ -133,7 +146,6 @@ protected:
|
||||
QRect m_dockGeometry;
|
||||
QPoint m_originPoint;
|
||||
QSize m_iconSize;
|
||||
Dock::TipsWidget *m_removeTips;
|
||||
QScopedPointer<DockPopupWindow> m_popupWindow;
|
||||
/**
|
||||
* @brief m_distanceMultiple: 倍数
|
||||
@ -143,6 +155,8 @@ protected:
|
||||
|
||||
bool m_bDragDrop = false; // 图标是否被拖拽
|
||||
DockItem *m_item;
|
||||
QRect m_lastMouseGeometry;
|
||||
DockScreen *m_dockScreen;
|
||||
};
|
||||
|
||||
class QuickDragWidget : public AppDragWidget
|
||||
@ -160,6 +174,9 @@ public:
|
||||
protected:
|
||||
void dropEvent(QDropEvent *event) override;
|
||||
void dragMoveEvent(QDragMoveEvent *event) override;
|
||||
|
||||
private:
|
||||
bool isRemoveAble(const QPoint &curPos);
|
||||
};
|
||||
|
||||
#endif /* APPDRAGWIDGET_H */
|
||||
|
60
frame/screenspliter/screenspliter.cpp
Normal file
60
frame/screenspliter/screenspliter.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd.
|
||||
*
|
||||
* Author: donghualin <donghualin@uniontech.com>
|
||||
*
|
||||
* Maintainer: donghualin <donghualin@uniontech.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "screenspliter.h"
|
||||
#include "appitem.h"
|
||||
#include "utils.h"
|
||||
#include "screenspliter_xcb.h"
|
||||
#include "screenspliter_wayland.h"
|
||||
|
||||
bool ScreenSpliter::releaseSplit()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
ScreenSpliter::ScreenSpliter(AppItem *appItem, DockEntryInter *entryInter, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_appItem(appItem)
|
||||
, m_entryInter(entryInter)
|
||||
{
|
||||
}
|
||||
|
||||
ScreenSpliter::~ScreenSpliter()
|
||||
{
|
||||
m_appItem = nullptr;
|
||||
}
|
||||
|
||||
AppItem *ScreenSpliter::appItem() const
|
||||
{
|
||||
return m_appItem;
|
||||
}
|
||||
|
||||
DockEntryInter *ScreenSpliter::entryInter() const
|
||||
{
|
||||
return m_entryInter;
|
||||
}
|
||||
|
||||
ScreenSpliter *ScreenSpliterFactory::createScreenSpliter(AppItem *appItem, DockEntryInter *entryInter)
|
||||
{
|
||||
if (Utils::IS_WAYLAND_DISPLAY)
|
||||
return new ScreenSpliter_Wayland(appItem, entryInter, appItem);
|
||||
|
||||
return new ScreenSpliter_Xcb(appItem, entryInter, appItem);
|
||||
}
|
71
frame/screenspliter/screenspliter.h
Normal file
71
frame/screenspliter/screenspliter.h
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd.
|
||||
*
|
||||
* Author: donghualin <donghualin@uniontech.com>
|
||||
*
|
||||
* Maintainer: donghualin <donghualin@uniontech.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef SCREENSPLITER_H
|
||||
#define SCREENSPLITER_H
|
||||
|
||||
#include "dbusutil.h"
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class AppItem;
|
||||
|
||||
class ScreenSpliter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum SplitDirection {
|
||||
None, // 无操作
|
||||
Left, // 左分屏
|
||||
Right, // 右分屏
|
||||
Top, // 上分屏
|
||||
Bottom, // 下分屏
|
||||
LeftTop, // 左上
|
||||
RightTop, // 右上
|
||||
LeftBottom, // 左下
|
||||
RightBottom, // 右下
|
||||
Full // 全屏
|
||||
};
|
||||
|
||||
public:
|
||||
virtual void startSplit(const QRect &) = 0; // 触发分屏提示效果
|
||||
virtual bool split(SplitDirection) = 0; // 开始触发分屏
|
||||
virtual bool suportSplitScreen() = 0; // 是否支持分屏
|
||||
virtual bool releaseSplit(); // 释放分屏
|
||||
|
||||
protected:
|
||||
explicit ScreenSpliter(AppItem *appItem, DockEntryInter *entryInter, QObject *parent = nullptr);
|
||||
virtual ~ScreenSpliter();
|
||||
AppItem *appItem() const;
|
||||
DockEntryInter *entryInter() const;
|
||||
|
||||
private:
|
||||
AppItem *m_appItem;
|
||||
DockEntryInter *m_entryInter;
|
||||
};
|
||||
|
||||
class ScreenSpliterFactory
|
||||
{
|
||||
public:
|
||||
static ScreenSpliter *createScreenSpliter(AppItem *appItem, DockEntryInter *entryInter);
|
||||
};
|
||||
|
||||
#endif // SCREENSPLITER_H
|
247
frame/screenspliter/screenspliter_wayland.cpp
Normal file
247
frame/screenspliter/screenspliter_wayland.cpp
Normal file
@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd.
|
||||
*
|
||||
* Author: donghualin <donghualin@uniontech.com>
|
||||
*
|
||||
* Maintainer: donghualin <donghualin@uniontech.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "screenspliter_wayland.h"
|
||||
#include "appitem.h"
|
||||
|
||||
#include <QWindow>
|
||||
#include <QApplication>
|
||||
#include <QX11Info>
|
||||
#include <QtWaylandClient>
|
||||
#define private public
|
||||
#include <private/qwaylandintegration_p.h>
|
||||
#include <private/qwaylandshellsurface_p.h>
|
||||
#include <private/qwaylandwindow_p.h>
|
||||
#include <private/qwaylandcursor_p.h>
|
||||
#undef private
|
||||
|
||||
#include <registry.h>
|
||||
#include <ddeshell.h>
|
||||
#include <event_queue.h>
|
||||
#include <plasmashell.h>
|
||||
#include <compositor.h>
|
||||
#include <clientmanagement.h>
|
||||
#include <connection_thread.h>
|
||||
|
||||
SplitWindowManager *ScreenSpliter_Wayland::m_splitManager = nullptr;
|
||||
|
||||
/** wayland下的分屏功能
|
||||
* @brief ScreenSpliter_Wayland::ScreenSpliter_Wayland
|
||||
* @param parent
|
||||
*/
|
||||
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()
|
||||
{
|
||||
}
|
||||
|
||||
void ScreenSpliter_Wayland::startSplit(const QRect &rect)
|
||||
{
|
||||
if (entryInter()->windowInfos().size() == 0) {
|
||||
// 如果默认打开的子窗口的数量为0,则无需操作,同时记录标记,在打开新的窗口的时候,设置遮罩
|
||||
m_splitRect = rect;
|
||||
entryInter()->Activate(QX11Info::getTimestamp());
|
||||
return;
|
||||
}
|
||||
|
||||
setMaskVisible(rect, true);
|
||||
}
|
||||
|
||||
void ScreenSpliter_Wayland::setMaskVisible(const QRect &rect, bool visible)
|
||||
{
|
||||
static QWidget *desktopWidget = nullptr;
|
||||
if (!desktopWidget) {
|
||||
desktopWidget = new QWidget;
|
||||
DPalette palette = DGuiApplicationHelper::instance()->applicationPalette();
|
||||
QColor backColor = palette.color(QPalette::Highlight);
|
||||
backColor.setAlpha(255 * 0.3);
|
||||
palette.setBrush(QPalette::ColorRole::Background, backColor);
|
||||
desktopWidget->setPalette(palette);
|
||||
desktopWidget->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool);
|
||||
}
|
||||
desktopWidget->setVisible(visible);
|
||||
desktopWidget->setGeometry(rect);
|
||||
desktopWidget->raise();
|
||||
}
|
||||
|
||||
bool ScreenSpliter_Wayland::split(SplitDirection direction)
|
||||
{
|
||||
setMaskVisible(QRect(), false);
|
||||
const QString windowUuid = splitUuid();
|
||||
if (windowUuid.isEmpty())
|
||||
return false;
|
||||
|
||||
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;
|
||||
|
||||
// 如果存在未打开的窗口,就默认让其认为支持,后续会根据这个来打开一个新的窗口
|
||||
if (entryInter()->windowInfos().size() == 0)
|
||||
return true;
|
||||
|
||||
// 如果存在已经打开的窗口
|
||||
m_checkedNotSupport = splitUuid().isEmpty();
|
||||
return (!m_checkedNotSupport);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief SplitWindowManager::SplitWindowManager
|
||||
* @param wayland下的分屏的管理
|
||||
*/
|
||||
SplitWindowManager::SplitWindowManager(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_clientManagement(nullptr)
|
||||
, m_connectionThread(new QThread(nullptr))
|
||||
, m_connectionThreadObject(new ConnectionThread)
|
||||
{
|
||||
connect(m_connectionThreadObject, &ConnectionThread::connected, this, &SplitWindowManager::onConnectionFinished, Qt::QueuedConnection);
|
||||
|
||||
m_connectionThreadObject->moveToThread(m_connectionThread);
|
||||
m_connectionThread->start();
|
||||
m_connectionThreadObject->initConnection();
|
||||
}
|
||||
|
||||
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)
|
||||
return true;
|
||||
};
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static ClientManagement::SplitType convertSplitType(ScreenSpliter::SplitDirection direction)
|
||||
{
|
||||
static QMap<ScreenSpliter::SplitDirection, ClientManagement::SplitType> direcionMapping = {
|
||||
{ ScreenSpliter::Left, ClientManagement::SplitType::Left },
|
||||
{ ScreenSpliter::Right, ClientManagement::SplitType::Right},
|
||||
{ ScreenSpliter::Top, ClientManagement::SplitType::Top },
|
||||
{ ScreenSpliter::Bottom, ClientManagement::SplitType::Bottom },
|
||||
{ ScreenSpliter::LeftTop, ClientManagement::SplitType::LeftTop },
|
||||
{ ScreenSpliter::RightTop, ClientManagement::SplitType::RightTop },
|
||||
{ ScreenSpliter::LeftBottom, ClientManagement::SplitType::LeftBottom },
|
||||
{ ScreenSpliter::RightBottom, ClientManagement::SplitType::RightBottom }
|
||||
};
|
||||
|
||||
return direcionMapping.value(direction, ClientManagement::SplitType::None);
|
||||
}
|
||||
|
||||
void SplitWindowManager::requestSplitWindow(const char *uuid, const ScreenSpliter::SplitDirection &direction)
|
||||
{
|
||||
m_clientManagement->requestSplitWindow(uuid, convertSplitType(direction));
|
||||
}
|
||||
|
||||
void SplitWindowManager::onConnectionFinished()
|
||||
{
|
||||
EventQueue *eventQueue = new EventQueue(this);
|
||||
eventQueue->setup(m_connectionThreadObject);
|
||||
|
||||
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);
|
||||
registry->setup();
|
||||
}
|
103
frame/screenspliter/screenspliter_wayland.h
Normal file
103
frame/screenspliter/screenspliter_wayland.h
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd.
|
||||
*
|
||||
* Author: donghualin <donghualin@uniontech.com>
|
||||
*
|
||||
* Maintainer: donghualin <donghualin@uniontech.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef SCREENSPLITER_WAYLAND_H
|
||||
#define SCREENSPLITER_WAYLAND_H
|
||||
|
||||
#include "screenspliter.h"
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
namespace KWayland {
|
||||
namespace Client {
|
||||
class Registry;
|
||||
class DDEShell;
|
||||
class DDEShellSurface;
|
||||
class EventQueue;
|
||||
class Compositor;
|
||||
class Surface;
|
||||
class ClientManagement;
|
||||
class ConnectionThread;
|
||||
}
|
||||
}
|
||||
|
||||
class AppItem;
|
||||
class QWindow;
|
||||
class QThread;
|
||||
class SplitWindowManager;
|
||||
|
||||
class WindowInfo;
|
||||
typedef QMap<quint32, WindowInfo> WindowInfoMap;
|
||||
|
||||
using namespace KWayland::Client;
|
||||
|
||||
class ScreenSpliter_Wayland : public ScreenSpliter
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ScreenSpliter_Wayland(AppItem *appItem, DockEntryInter *entryInter, QObject *parent);
|
||||
~ScreenSpliter_Wayland() override;
|
||||
|
||||
void startSplit(const QRect &rect) override;
|
||||
bool split(SplitDirection direction) override;
|
||||
bool suportSplitScreen() override;
|
||||
|
||||
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
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
friend class ScreenSpliter_Wayland;
|
||||
|
||||
protected:
|
||||
explicit SplitWindowManager(QObject *parent = Q_NULLPTR);
|
||||
~SplitWindowManager() override;
|
||||
|
||||
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();
|
||||
|
||||
private:
|
||||
ClientManagement *m_clientManagement;
|
||||
QThread *m_connectionThread;
|
||||
ConnectionThread *m_connectionThreadObject;
|
||||
};
|
||||
|
||||
#endif // SCREENSPLITER_WAYLAND_H
|
240
frame/screenspliter/screenspliter_xcb.cpp
Normal file
240
frame/screenspliter/screenspliter_xcb.cpp
Normal file
@ -0,0 +1,240 @@
|
||||
/*
|
||||
* Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd.
|
||||
*
|
||||
* Author: donghualin <donghualin@uniontech.com>
|
||||
*
|
||||
* Maintainer: donghualin <donghualin@uniontech.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#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;
|
||||
}
|
||||
|
||||
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;
|
||||
return;
|
||||
}
|
||||
showSplitScreenEffect(rect, true);
|
||||
}
|
||||
|
||||
bool ScreenSpliter_Xcb::split(ScreenSpliter::SplitDirection direction)
|
||||
{
|
||||
showSplitScreenEffect(QRect(), false);
|
||||
if (!openWindow())
|
||||
return false;
|
||||
|
||||
// 如果当前的应用不支持分屏,也无需分屏,检查分屏的时候至少需要一个窗口,因此这里写在打开窗口之后
|
||||
quint32 WId = splittingWindowWId();
|
||||
if (WId == 0) {
|
||||
// 如果当前存在主动打开的窗口,那么就关闭当前主动打开的窗口
|
||||
if (m_isSplitCreateWindow) {
|
||||
entryInter()->ForceQuit();
|
||||
m_isSplitCreateWindow = false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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 不进入预览
|
||||
|
||||
xcb_send_event(QX11Info::connection(), false, QX11Info::appRootWindow(QX11Info::appScreen()),
|
||||
SubstructureNotifyMask, (const char *)&xev);
|
||||
xcb_flush(QX11Info::connection());
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
return;
|
||||
|
||||
// 触发分屏的效果
|
||||
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());
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
return (splittingWindowWId() != 0);
|
||||
}
|
||||
|
||||
bool ScreenSpliter_Xcb::releaseSplit()
|
||||
{
|
||||
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()
|
||||
{
|
||||
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);
|
||||
|
||||
bool supported = false;
|
||||
if (const char *cdata = data.constData())
|
||||
supported = *(reinterpret_cast<const quint8 *>(cdata));
|
||||
|
||||
return supported ? WId : 0;
|
||||
}
|
55
frame/screenspliter/screenspliter_xcb.h
Normal file
55
frame/screenspliter/screenspliter_xcb.h
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd.
|
||||
*
|
||||
* Author: donghualin <donghualin@uniontech.com>
|
||||
*
|
||||
* Maintainer: donghualin <donghualin@uniontech.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef SCREENSPLITER_XCB_H
|
||||
#define SCREENSPLITER_XCB_H
|
||||
|
||||
#include "screenspliter.h"
|
||||
|
||||
#include <QRect>
|
||||
|
||||
class WindowInfo;
|
||||
typedef QMap<quint32, WindowInfo> WindowInfoMap;
|
||||
|
||||
class ScreenSpliter_Xcb : public ScreenSpliter
|
||||
{
|
||||
public:
|
||||
explicit ScreenSpliter_Xcb(AppItem *appItem, DockEntryInter *entryInter, QObject *parent = nullptr);
|
||||
|
||||
void startSplit(const QRect &rect) override;
|
||||
bool split(ScreenSpliter::SplitDirection direction) override;
|
||||
bool suportSplitScreen() override;
|
||||
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;
|
||||
};
|
||||
|
||||
#endif // SCREENSPLITER_XCB_H
|
@ -47,17 +47,16 @@
|
||||
#include <QLabel>
|
||||
#include <QPixmap>
|
||||
#include <QtConcurrent/QtConcurrentRun>
|
||||
#include <QX11Info>
|
||||
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
#include <qpa/qplatformintegration.h>
|
||||
#define protected public
|
||||
#include <QtGui/private/qsimpledrag_p.h>
|
||||
#undef protected
|
||||
#include <QtGui/private/qshapedpixmapdndwindow_p.h>
|
||||
#include <QtGui/private/qguiapplication_p.h>
|
||||
|
||||
#include <DGuiApplicationHelper>
|
||||
#include <DWindowManagerHelper>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
#define SPLITER_SIZE 2
|
||||
#define TRASH_MARGIN 20
|
||||
#define PLUGIN_MAX_SIZE 40
|
||||
@ -794,8 +793,25 @@ void MainPanelControl::startDrag(DockItem *dockItem)
|
||||
|
||||
m_appDragWidget = appDrag->appDragWidget();
|
||||
|
||||
connect(m_appDragWidget, &AppDragWidget::requestChangedArea, this, [ = ](QRect rect) {
|
||||
// 在区域改变的时候,出现分屏提示效果
|
||||
AppItem *appItem = static_cast<AppItem *>(dockItem);
|
||||
if (appItem->supportSplitWindow())
|
||||
appItem->startSplit(rect);
|
||||
});
|
||||
|
||||
connect(m_appDragWidget, &AppDragWidget::requestSplitWindow, this, [ = ](ScreenSpliter::SplitDirection dir) {
|
||||
AppItem *appItem = static_cast<AppItem *>(dockItem);
|
||||
if (appItem->supportSplitWindow())
|
||||
appItem->splitWindowOnScreen(dir);
|
||||
});
|
||||
|
||||
connect(m_appDragWidget, &AppDragWidget::destroyed, this, [ = ] {
|
||||
m_appDragWidget = nullptr;
|
||||
AppItem *appItem = static_cast<AppItem *>(dockItem);
|
||||
if (appItem->supportSplitWindow())
|
||||
return;
|
||||
|
||||
if (!item.isNull() && qobject_cast<AppItem *>(item)->isValid()) {
|
||||
// 如果是从最近打开区域移动到应用区域的,则需要将其固定
|
||||
dockRecentApp(item);
|
||||
@ -811,13 +827,6 @@ void MainPanelControl::startDrag(DockItem *dockItem)
|
||||
}
|
||||
});
|
||||
|
||||
connect(m_appDragWidget, &AppDragWidget::requestRemoveItem, this, [ = ] {
|
||||
if (-1 != m_appAreaSonLayout->indexOf(item)) {
|
||||
m_dragIndex = m_appAreaSonLayout->indexOf(item);
|
||||
removeItem(item);
|
||||
}
|
||||
});
|
||||
|
||||
appDrag->appDragWidget()->setOriginPos((m_appAreaSonWidget->mapToGlobal(item->pos())));
|
||||
appDrag->appDragWidget()->setDockInfo(m_position, QRect(mapToGlobal(pos()), size()));
|
||||
const QPixmap &dragPix = qobject_cast<AppItem *>(item)->appIcon();
|
||||
@ -852,6 +861,11 @@ void MainPanelControl::startDrag(DockItem *dockItem)
|
||||
drag->setMimeData(new QMimeData);
|
||||
drag->exec(Qt::MoveAction);
|
||||
|
||||
if (item->itemType() == DockItem::App && m_appDragWidget) {
|
||||
// TODO AppDragWidget中偶尔会出现拖拽结束后没有触发dropEvent的情况,因此exec结束后处理dropEvent中未执行的操作(临时处理方式)
|
||||
m_appDragWidget->execFinished();
|
||||
}
|
||||
|
||||
if (item->itemType() != DockItem::App || m_dragIndex == -1) {
|
||||
m_appDragWidget = nullptr;
|
||||
item->setDraging(false);
|
||||
@ -1368,8 +1382,7 @@ void MainPanelControl::calcuDockIconSize(int w, int h, int traySize)
|
||||
if (!layout || !layout->itemAt(0))
|
||||
continue;
|
||||
|
||||
PluginsItem *pItem = static_cast<PluginsItem *>(layout->itemAt(0)->widget());
|
||||
qInfo() << pItem->pluginItem()->pluginDisplayName();
|
||||
PluginsItem *pItem = qobject_cast<PluginsItem *>(layout->itemAt(0)->widget());
|
||||
if (!pItem)
|
||||
continue;
|
||||
|
||||
|
@ -282,7 +282,7 @@ void QuickPluginWindow::startDrag(PluginsItemInterface *moveItem)
|
||||
drag->setPixmap(dragPixmap);
|
||||
drag->setHotSpot(QPoint(0, 0));
|
||||
|
||||
connect(drag->appDragWidget(), &AppDragWidget::requestRemoveItem, this, [ this, moveItem ] {
|
||||
connect(drag->appDragWidget(), &AppDragWidget::requestSplitWindow, this, [ this, moveItem ] {
|
||||
removePlugin(moveItem);
|
||||
});
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user