2020-01-17 17:23:40 +08:00
|
|
|
/* BEGIN_COMMON_COPYRIGHT_HEADER
|
|
|
|
|
* (c)LGPL2+
|
|
|
|
|
*
|
|
|
|
|
* Copyright: 2011 Razor team
|
2020-03-14 22:27:32 +08:00
|
|
|
* 2014 LXQt team
|
2020-01-17 17:23:40 +08:00
|
|
|
* Authors:
|
|
|
|
|
* Alexander Sokoloff <sokoloff.a@gmail.com>
|
|
|
|
|
* Kuzma Shapran <kuzma.shapran@gmail.com>
|
|
|
|
|
*
|
2020-01-19 10:27:16 +08:00
|
|
|
* Copyright: 2019 Tianjin KYLIN Information Technology Co., Ltd. *
|
2020-01-17 17:23:40 +08:00
|
|
|
*
|
|
|
|
|
* This program or library is free software; you can redistribute it
|
|
|
|
|
* and/or modify it under the terms of the GNU Lesser General Public
|
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This library 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
|
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
|
|
|
|
|
|
* You should have received a copy of the GNU Lesser General
|
|
|
|
|
* Public License along with this library; if not, write to the
|
|
|
|
|
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
|
* Boston, MA 02110-1301 USA
|
|
|
|
|
*
|
|
|
|
|
* END_COMMON_COPYRIGHT_HEADER */
|
|
|
|
|
|
|
|
|
|
#include "ukuitaskbutton.h"
|
|
|
|
|
#include "ukuitaskgroup.h"
|
|
|
|
|
#include "ukuitaskbar.h"
|
|
|
|
|
|
|
|
|
|
//#include <UKUi/Settings>
|
|
|
|
|
#include "../panel/common/ukuisettings.h"
|
|
|
|
|
|
|
|
|
|
#include <QDebug>
|
|
|
|
|
#include <QTimer>
|
|
|
|
|
#include <QMenu>
|
|
|
|
|
#include <QAction>
|
|
|
|
|
#include <QContextMenuEvent>
|
|
|
|
|
#include <QPainter>
|
|
|
|
|
#include <QDrag>
|
|
|
|
|
#include <QMouseEvent>
|
|
|
|
|
#include <QMimeData>
|
|
|
|
|
#include <QApplication>
|
|
|
|
|
#include <QDragEnterEvent>
|
|
|
|
|
#include <QStylePainter>
|
|
|
|
|
#include <QStyleOptionToolButton>
|
|
|
|
|
#include <QDesktopWidget>
|
|
|
|
|
|
2021-03-10 10:46:56 +08:00
|
|
|
#include <unistd.h>
|
2020-01-17 17:23:40 +08:00
|
|
|
#include "ukuitaskgroup.h"
|
|
|
|
|
#include "ukuitaskbar.h"
|
2020-05-28 09:16:40 +08:00
|
|
|
#include "../panel/customstyle.h"
|
2020-01-17 17:23:40 +08:00
|
|
|
#include <KWindowSystem/KWindowSystem>
|
|
|
|
|
// Necessary for closeApplication()
|
|
|
|
|
#include <KWindowSystem/NETWM>
|
|
|
|
|
#include <QtX11Extras/QX11Info>
|
|
|
|
|
|
2020-06-12 17:07:20 +08:00
|
|
|
#define PANEL_SETTINGS "org.ukui.panel.settings"
|
|
|
|
|
#define PANEL_SIZE_KEY "panelsize"
|
|
|
|
|
#define ICON_SIZE_KEY "iconsize"
|
|
|
|
|
#define PANEL_POSITION_KEY "panelposition"
|
|
|
|
|
|
2020-01-17 17:23:40 +08:00
|
|
|
bool UKUITaskButton::sDraggging = false;
|
|
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
|
|
|
|
|
|
************************************************/
|
|
|
|
|
void LeftAlignedTextStyle::drawItemText(QPainter * painter, const QRect & rect, int flags
|
|
|
|
|
, const QPalette & pal, bool enabled, const QString & text
|
|
|
|
|
, QPalette::ColorRole textRole) const
|
|
|
|
|
{
|
|
|
|
|
QString txt = QFontMetrics(painter->font()).elidedText(text, Qt::ElideRight, rect.width());
|
|
|
|
|
return QProxyStyle::drawItemText(painter, rect, (flags & ~Qt::AlignHCenter) | Qt::AlignLeft, pal, enabled, txt, textRole);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
|
|
|
|
|
|
************************************************/
|
2020-05-28 11:45:18 +08:00
|
|
|
UKUITaskButton::UKUITaskButton(QString appName,const WId window, UKUITaskBar * taskbar, QWidget *parent) :
|
2020-01-17 17:23:40 +08:00
|
|
|
QToolButton(parent),
|
|
|
|
|
mWindow(window),
|
2020-05-28 11:45:18 +08:00
|
|
|
mAppName(appName),
|
2020-01-17 17:23:40 +08:00
|
|
|
mUrgencyHint(false),
|
|
|
|
|
mOrigin(Qt::TopLeftCorner),
|
|
|
|
|
mDrawPixmap(false),
|
|
|
|
|
mParentTaskBar(taskbar),
|
|
|
|
|
mPlugin(mParentTaskBar->plugin()),
|
|
|
|
|
mDNDTimer(new QTimer(this))
|
|
|
|
|
{
|
|
|
|
|
Q_ASSERT(taskbar);
|
2020-03-01 22:46:04 +08:00
|
|
|
taskbuttonstatus=NORMAL;
|
2020-01-17 17:23:40 +08:00
|
|
|
|
|
|
|
|
setCheckable(true);
|
|
|
|
|
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
|
|
|
|
|
|
|
|
|
setMinimumWidth(1);
|
|
|
|
|
setMinimumHeight(1);
|
|
|
|
|
setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
|
|
|
|
|
setAcceptDrops(true);
|
|
|
|
|
|
|
|
|
|
updateText();
|
|
|
|
|
updateIcon();
|
|
|
|
|
|
|
|
|
|
mDNDTimer->setSingleShot(true);
|
|
|
|
|
mDNDTimer->setInterval(700);
|
|
|
|
|
connect(mDNDTimer, SIGNAL(timeout()), this, SLOT(activateWithDraggable()));
|
|
|
|
|
connect(UKUi::Settings::globalSettings(), SIGNAL(iconThemeChanged()), this, SLOT(updateIcon()));
|
|
|
|
|
connect(mParentTaskBar, &UKUITaskBar::iconByClassChanged, this, &UKUITaskButton::updateIcon);
|
2020-06-12 17:07:20 +08:00
|
|
|
|
|
|
|
|
const QByteArray id(PANEL_SETTINGS);
|
|
|
|
|
gsettings = new QGSettings(id);
|
|
|
|
|
connect(gsettings, &QGSettings::changed, this, [=] (const QString &key){
|
|
|
|
|
if (key == PANEL_SIZE_KEY)
|
|
|
|
|
{
|
|
|
|
|
updateIcon();
|
|
|
|
|
}
|
|
|
|
|
});
|
2021-01-30 18:21:51 +08:00
|
|
|
|
|
|
|
|
QStringList windowList;
|
2021-06-18 21:29:16 +08:00
|
|
|
//qDebug()<<"Window Name"<<KWindowInfo(this->windowId(), 0, NET::WM2WindowClass).windowClassClass();
|
2021-01-30 18:21:51 +08:00
|
|
|
windowList<<"kylin-kmre-window"<<"kydroid-display-window";
|
|
|
|
|
if(windowList.contains(KWindowInfo(this->windowId(), 0, NET::WM2WindowClass).windowClassClass())){
|
|
|
|
|
connect(KWindowSystem::self(), static_cast<void (KWindowSystem::*)(WId, NET::Properties, NET::Properties2)>(&KWindowSystem::windowChanged)
|
2020-12-28 16:09:34 +08:00
|
|
|
, this, &UKUITaskButton::updateIcon);
|
2021-01-30 18:21:51 +08:00
|
|
|
}
|
2020-01-17 17:23:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
|
|
|
|
|
|
************************************************/
|
|
|
|
|
UKUITaskButton::~UKUITaskButton()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
|
|
|
|
|
|
************************************************/
|
|
|
|
|
void UKUITaskButton::updateText()
|
|
|
|
|
{
|
|
|
|
|
KWindowInfo info(mWindow, NET::WMVisibleName | NET::WMName);
|
|
|
|
|
QString title = info.visibleName().isEmpty() ? info.name() : info.visibleName();
|
|
|
|
|
setText(title.replace("&", "&&"));
|
|
|
|
|
setToolTip(title);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-28 09:16:40 +08:00
|
|
|
/* int devicePixels = mPlugin->panel()->iconSize() * devicePixelRatioF()是由ico =KWindowSystem:ico(mwindow)更改的
|
|
|
|
|
* 目的是为了能够显示正确的application-x-desktop的图标的大小
|
2020-06-12 17:07:20 +08:00
|
|
|
*
|
2020-05-28 09:16:40 +08:00
|
|
|
*/
|
2021-01-11 09:56:06 +08:00
|
|
|
void UKUITaskButton::setLeaderWindow(WId leaderWindow) {
|
|
|
|
|
mWindow = leaderWindow;
|
2021-06-03 21:36:54 +08:00
|
|
|
updateIcon();
|
2021-01-11 09:56:06 +08:00
|
|
|
}
|
|
|
|
|
|
2020-01-17 17:23:40 +08:00
|
|
|
void UKUITaskButton::updateIcon()
|
|
|
|
|
{
|
2020-12-28 11:58:29 +08:00
|
|
|
if (mAppName == QString("emo-system-ShellMethods") ||
|
|
|
|
|
mAppName == QString("Qq"))
|
|
|
|
|
sleep(1);
|
2021-02-02 11:50:41 +08:00
|
|
|
|
2020-01-17 17:23:40 +08:00
|
|
|
QIcon ico;
|
2020-06-12 17:07:20 +08:00
|
|
|
int mIconSize=mPlugin->panel()->iconSize();
|
2020-01-17 17:23:40 +08:00
|
|
|
if (mParentTaskBar->isIconByClass())
|
|
|
|
|
{
|
2020-08-17 14:43:42 +08:00
|
|
|
ico = QIcon::fromTheme(QString::fromUtf8(KWindowInfo{mWindow, 0, NET::WM2WindowClass}.windowClassClass()).toLower());
|
2020-01-17 17:23:40 +08:00
|
|
|
}
|
|
|
|
|
if (ico.isNull())
|
|
|
|
|
{
|
2020-06-12 17:07:20 +08:00
|
|
|
#if QT_VERSION >= 0x050600
|
|
|
|
|
int devicePixels = mIconSize * devicePixelRatioF();
|
2020-05-28 09:16:40 +08:00
|
|
|
#else
|
2020-06-12 17:07:20 +08:00
|
|
|
int devicePixels = mIconSize * devicePixelRatio();
|
2020-05-28 09:16:40 +08:00
|
|
|
#endif
|
|
|
|
|
ico = KWindowSystem::icon(mWindow, devicePixels, devicePixels);
|
2020-01-17 17:23:40 +08:00
|
|
|
}
|
2021-01-09 17:04:30 +08:00
|
|
|
if (mIcon.isNull()) {
|
2020-12-28 11:58:29 +08:00
|
|
|
mIcon = QIcon::fromTheme("application-x-desktop");
|
2021-01-09 17:04:30 +08:00
|
|
|
}
|
2021-01-11 09:56:06 +08:00
|
|
|
if (ico.isNull()) {
|
2021-01-09 17:04:30 +08:00
|
|
|
ico = mIcon;
|
2021-01-11 09:56:06 +08:00
|
|
|
}
|
2021-01-09 17:04:30 +08:00
|
|
|
setIcon(ico);
|
2020-06-12 17:07:20 +08:00
|
|
|
setIconSize(QSize(mIconSize,mIconSize));
|
2020-01-17 17:23:40 +08:00
|
|
|
}
|
|
|
|
|
|
2020-12-28 11:58:29 +08:00
|
|
|
void UKUITaskButton::setGroupIcon(QIcon ico)
|
|
|
|
|
{
|
|
|
|
|
mIcon = ico;
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-17 17:23:40 +08:00
|
|
|
/************************************************
|
|
|
|
|
|
|
|
|
|
************************************************/
|
|
|
|
|
void UKUITaskButton::refreshIconGeometry(QRect const & geom)
|
|
|
|
|
{
|
|
|
|
|
NETWinInfo info(QX11Info::connection(),
|
|
|
|
|
windowId(),
|
|
|
|
|
(WId) QX11Info::appRootWindow(),
|
|
|
|
|
NET::WMIconGeometry,
|
|
|
|
|
0);
|
|
|
|
|
NETRect const curr = info.iconGeometry();
|
|
|
|
|
if (curr.pos.x != geom.x() || curr.pos.y != geom.y()
|
|
|
|
|
|| curr.size.width != geom.width() || curr.size.height != geom.height())
|
|
|
|
|
{
|
|
|
|
|
NETRect nrect;
|
|
|
|
|
nrect.pos.x = geom.x();
|
|
|
|
|
nrect.pos.y = geom.y();
|
|
|
|
|
nrect.size.height = geom.height();
|
|
|
|
|
nrect.size.width = geom.width();
|
|
|
|
|
info.setIconGeometry(nrect);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
|
|
|
|
|
|
************************************************/
|
|
|
|
|
void UKUITaskButton::dragEnterEvent(QDragEnterEvent *event)
|
|
|
|
|
{
|
|
|
|
|
// It must be here otherwise dragLeaveEvent and dragMoveEvent won't be called
|
|
|
|
|
// on the other hand drop and dragmove events of parent widget won't be called
|
|
|
|
|
event->acceptProposedAction();
|
|
|
|
|
if (event->mimeData()->hasFormat(mimeDataFormat()))
|
|
|
|
|
{
|
|
|
|
|
emit dragging(event->source(), event->pos());
|
|
|
|
|
setAttribute(Qt::WA_UnderMouse, false);
|
|
|
|
|
} else
|
|
|
|
|
{
|
|
|
|
|
mDNDTimer->start();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QToolButton::dragEnterEvent(event);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UKUITaskButton::dragMoveEvent(QDragMoveEvent * event)
|
|
|
|
|
{
|
|
|
|
|
if (event->mimeData()->hasFormat(mimeDataFormat()))
|
|
|
|
|
{
|
|
|
|
|
emit dragging(event->source(), event->pos());
|
|
|
|
|
setAttribute(Qt::WA_UnderMouse, false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UKUITaskButton::dragLeaveEvent(QDragLeaveEvent *event)
|
|
|
|
|
{
|
|
|
|
|
mDNDTimer->stop();
|
|
|
|
|
QToolButton::dragLeaveEvent(event);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UKUITaskButton::dropEvent(QDropEvent *event)
|
|
|
|
|
{
|
|
|
|
|
mDNDTimer->stop();
|
|
|
|
|
if (event->mimeData()->hasFormat(mimeDataFormat()))
|
|
|
|
|
{
|
|
|
|
|
emit dropped(event->source(), event->pos());
|
|
|
|
|
setAttribute(Qt::WA_UnderMouse, false);
|
|
|
|
|
}
|
|
|
|
|
QToolButton::dropEvent(event);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
|
|
|
|
|
|
************************************************/
|
|
|
|
|
void UKUITaskButton::mousePressEvent(QMouseEvent* event)
|
|
|
|
|
{
|
|
|
|
|
const Qt::MouseButton b = event->button();
|
|
|
|
|
|
|
|
|
|
if (Qt::LeftButton == b)
|
|
|
|
|
mDragStartPosition = event->pos();
|
|
|
|
|
else if (Qt::MidButton == b && parentTaskBar()->closeOnMiddleClick())
|
|
|
|
|
closeApplication();
|
|
|
|
|
|
|
|
|
|
QToolButton::mousePressEvent(event);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
|
|
|
|
|
|
************************************************/
|
|
|
|
|
void UKUITaskButton::mouseReleaseEvent(QMouseEvent* event)
|
|
|
|
|
{
|
2020-03-25 16:22:07 +08:00
|
|
|
// if (event->button() == Qt::LeftButton)
|
|
|
|
|
// {
|
|
|
|
|
// if (isChecked())
|
|
|
|
|
// minimizeApplication();
|
|
|
|
|
// else
|
|
|
|
|
// {
|
|
|
|
|
// raiseApplication();
|
|
|
|
|
// }
|
|
|
|
|
// }
|
2020-01-17 17:23:40 +08:00
|
|
|
QToolButton::mouseReleaseEvent(event);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
|
|
|
|
|
|
************************************************/
|
|
|
|
|
QMimeData * UKUITaskButton::mimeData()
|
|
|
|
|
{
|
|
|
|
|
QMimeData *mimedata = new QMimeData;
|
|
|
|
|
QByteArray ba;
|
|
|
|
|
QDataStream stream(&ba,QIODevice::WriteOnly);
|
|
|
|
|
stream << (qlonglong)(mWindow);
|
|
|
|
|
mimedata->setData(mimeDataFormat(), ba);
|
|
|
|
|
return mimedata;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
|
|
|
|
|
|
************************************************/
|
|
|
|
|
void UKUITaskButton::mouseMoveEvent(QMouseEvent* event)
|
|
|
|
|
{
|
|
|
|
|
if (!(event->buttons() & Qt::LeftButton))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if ((event->pos() - mDragStartPosition).manhattanLength() < QApplication::startDragDistance())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
QDrag *drag = new QDrag(this);
|
|
|
|
|
drag->setMimeData(mimeData());
|
|
|
|
|
QIcon ico = icon();
|
|
|
|
|
QPixmap img = ico.pixmap(ico.actualSize({32, 32}));
|
|
|
|
|
drag->setPixmap(img);
|
|
|
|
|
switch (parentTaskBar()->panel()->position())
|
|
|
|
|
{
|
|
|
|
|
case IUKUIPanel::PositionLeft:
|
|
|
|
|
case IUKUIPanel::PositionTop:
|
|
|
|
|
drag->setHotSpot({0, 0});
|
|
|
|
|
break;
|
|
|
|
|
case IUKUIPanel::PositionRight:
|
|
|
|
|
case IUKUIPanel::PositionBottom:
|
|
|
|
|
drag->setHotSpot(img.rect().bottomRight());
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sDraggging = true;
|
|
|
|
|
drag->exec();
|
|
|
|
|
|
|
|
|
|
// if button is dropped out of panel (e.g. on desktop)
|
|
|
|
|
// it is not deleted automatically by Qt
|
|
|
|
|
drag->deleteLater();
|
|
|
|
|
sDraggging = false;
|
|
|
|
|
|
|
|
|
|
QAbstractButton::mouseMoveEvent(event);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
|
|
|
|
|
|
************************************************/
|
|
|
|
|
bool UKUITaskButton::isApplicationHidden() const
|
|
|
|
|
{
|
|
|
|
|
KWindowInfo info(mWindow, NET::WMState);
|
|
|
|
|
return (info.state() & NET::Hidden);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
|
|
|
|
|
|
************************************************/
|
|
|
|
|
bool UKUITaskButton::isApplicationActive() const
|
|
|
|
|
{
|
|
|
|
|
return KWindowSystem::activeWindow() == mWindow;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
|
|
|
|
|
|
************************************************/
|
|
|
|
|
void UKUITaskButton::activateWithDraggable()
|
|
|
|
|
{
|
|
|
|
|
// raise app in any time when there is a drag
|
|
|
|
|
// in progress to allow drop it into an app
|
|
|
|
|
raiseApplication();
|
|
|
|
|
KWindowSystem::forceActiveWindow(mWindow);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
|
|
|
|
|
|
************************************************/
|
|
|
|
|
void UKUITaskButton::raiseApplication()
|
|
|
|
|
{
|
|
|
|
|
KWindowInfo info(mWindow, NET::WMDesktop | NET::WMState | NET::XAWMState);
|
|
|
|
|
if (parentTaskBar()->raiseOnCurrentDesktop() && info.isMinimized())
|
|
|
|
|
{
|
|
|
|
|
KWindowSystem::setOnDesktop(mWindow, KWindowSystem::currentDesktop());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
int winDesktop = info.desktop();
|
|
|
|
|
if (KWindowSystem::currentDesktop() != winDesktop)
|
|
|
|
|
KWindowSystem::setCurrentDesktop(winDesktop);
|
|
|
|
|
}
|
|
|
|
|
KWindowSystem::activateWindow(mWindow);
|
|
|
|
|
|
|
|
|
|
setUrgencyHint(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
|
|
|
|
|
|
************************************************/
|
|
|
|
|
void UKUITaskButton::minimizeApplication()
|
|
|
|
|
{
|
|
|
|
|
KWindowSystem::minimizeWindow(mWindow);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
|
|
|
|
|
|
************************************************/
|
|
|
|
|
void UKUITaskButton::maximizeApplication()
|
|
|
|
|
{
|
|
|
|
|
QAction* act = qobject_cast<QAction*>(sender());
|
|
|
|
|
if (!act)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
int state = act->data().toInt();
|
|
|
|
|
switch (state)
|
|
|
|
|
{
|
|
|
|
|
case NET::MaxHoriz:
|
|
|
|
|
KWindowSystem::setState(mWindow, NET::MaxHoriz);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case NET::MaxVert:
|
|
|
|
|
KWindowSystem::setState(mWindow, NET::MaxVert);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
KWindowSystem::setState(mWindow, NET::Max);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!isApplicationActive())
|
|
|
|
|
raiseApplication();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
|
|
|
|
|
|
************************************************/
|
|
|
|
|
void UKUITaskButton::deMaximizeApplication()
|
|
|
|
|
{
|
|
|
|
|
KWindowSystem::clearState(mWindow, NET::Max);
|
|
|
|
|
|
|
|
|
|
if (!isApplicationActive())
|
|
|
|
|
raiseApplication();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
|
|
|
|
|
|
************************************************/
|
|
|
|
|
void UKUITaskButton::shadeApplication()
|
|
|
|
|
{
|
|
|
|
|
KWindowSystem::setState(mWindow, NET::Shaded);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
|
|
|
|
|
|
************************************************/
|
|
|
|
|
void UKUITaskButton::unShadeApplication()
|
|
|
|
|
{
|
|
|
|
|
KWindowSystem::clearState(mWindow, NET::Shaded);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
|
|
|
|
|
|
************************************************/
|
|
|
|
|
void UKUITaskButton::closeApplication()
|
|
|
|
|
{
|
|
|
|
|
// FIXME: Why there is no such thing in KWindowSystem??
|
|
|
|
|
NETRootInfo(QX11Info::connection(), NET::CloseWindow).closeWindowRequest(mWindow);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
|
|
|
|
|
|
************************************************/
|
|
|
|
|
void UKUITaskButton::setApplicationLayer()
|
|
|
|
|
{
|
|
|
|
|
QAction* act = qobject_cast<QAction*>(sender());
|
|
|
|
|
if (!act)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
int layer = act->data().toInt();
|
|
|
|
|
switch(layer)
|
|
|
|
|
{
|
|
|
|
|
case NET::KeepAbove:
|
|
|
|
|
KWindowSystem::clearState(mWindow, NET::KeepBelow);
|
|
|
|
|
KWindowSystem::setState(mWindow, NET::KeepAbove);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case NET::KeepBelow:
|
|
|
|
|
KWindowSystem::clearState(mWindow, NET::KeepAbove);
|
|
|
|
|
KWindowSystem::setState(mWindow, NET::KeepBelow);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
KWindowSystem::clearState(mWindow, NET::KeepBelow);
|
|
|
|
|
KWindowSystem::clearState(mWindow, NET::KeepAbove);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
|
|
|
|
|
|
************************************************/
|
|
|
|
|
void UKUITaskButton::moveApplicationToDesktop()
|
|
|
|
|
{
|
|
|
|
|
QAction* act = qobject_cast<QAction*>(sender());
|
|
|
|
|
if (!act)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
bool ok;
|
|
|
|
|
int desk = act->data().toInt(&ok);
|
|
|
|
|
|
|
|
|
|
if (!ok)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
KWindowSystem::setOnDesktop(mWindow, desk);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
|
|
|
|
|
|
************************************************/
|
|
|
|
|
void UKUITaskButton::moveApplication()
|
|
|
|
|
{
|
|
|
|
|
KWindowInfo info(mWindow, NET::WMDesktop);
|
|
|
|
|
if (!info.isOnCurrentDesktop())
|
|
|
|
|
KWindowSystem::setCurrentDesktop(info.desktop());
|
|
|
|
|
if (isMinimized())
|
|
|
|
|
KWindowSystem::unminimizeWindow(mWindow);
|
|
|
|
|
KWindowSystem::forceActiveWindow(mWindow);
|
|
|
|
|
const QRect& g = KWindowInfo(mWindow, NET::WMGeometry).geometry();
|
|
|
|
|
int X = g.center().x();
|
|
|
|
|
int Y = g.center().y();
|
|
|
|
|
QCursor::setPos(X, Y);
|
|
|
|
|
NETRootInfo(QX11Info::connection(), NET::WMMoveResize).moveResizeRequest(mWindow, X, Y, NET::Move);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
|
|
|
|
|
|
************************************************/
|
|
|
|
|
void UKUITaskButton::resizeApplication()
|
|
|
|
|
{
|
|
|
|
|
KWindowInfo info(mWindow, NET::WMDesktop);
|
|
|
|
|
if (!info.isOnCurrentDesktop())
|
|
|
|
|
KWindowSystem::setCurrentDesktop(info.desktop());
|
|
|
|
|
if (isMinimized())
|
|
|
|
|
KWindowSystem::unminimizeWindow(mWindow);
|
|
|
|
|
KWindowSystem::forceActiveWindow(mWindow);
|
|
|
|
|
const QRect& g = KWindowInfo(mWindow, NET::WMGeometry).geometry();
|
|
|
|
|
int X = g.bottomRight().x();
|
|
|
|
|
int Y = g.bottomRight().y();
|
|
|
|
|
QCursor::setPos(X, Y);
|
|
|
|
|
NETRootInfo(QX11Info::connection(), NET::WMMoveResize).moveResizeRequest(mWindow, X, Y, NET::BottomRight);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
|
|
|
|
|
|
************************************************/
|
|
|
|
|
void UKUITaskButton::contextMenuEvent(QContextMenuEvent* event)
|
|
|
|
|
{
|
|
|
|
|
if (event->modifiers().testFlag(Qt::ControlModifier))
|
|
|
|
|
{
|
|
|
|
|
event->ignore();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
KWindowInfo info(mWindow, 0, NET::WM2AllowedActions);
|
|
|
|
|
unsigned long state = KWindowInfo(mWindow, NET::WMState).state();
|
|
|
|
|
|
|
|
|
|
QMenu * menu = new QMenu(tr("Application"));
|
|
|
|
|
menu->setAttribute(Qt::WA_DeleteOnClose);
|
|
|
|
|
QAction* a;
|
|
|
|
|
|
|
|
|
|
/* KDE menu *******
|
|
|
|
|
|
|
|
|
|
+ To &Desktop >
|
|
|
|
|
+ &All Desktops
|
|
|
|
|
+ ---
|
|
|
|
|
+ &1 Desktop 1
|
|
|
|
|
+ &2 Desktop 2
|
|
|
|
|
+ &To Current Desktop
|
|
|
|
|
&Move
|
|
|
|
|
Re&size
|
|
|
|
|
+ Mi&nimize
|
|
|
|
|
+ Ma&ximize
|
|
|
|
|
+ &Shade
|
|
|
|
|
Ad&vanced >
|
|
|
|
|
Keep &Above Others
|
|
|
|
|
Keep &Below Others
|
|
|
|
|
Fill screen
|
|
|
|
|
&Layer >
|
|
|
|
|
Always on &top
|
|
|
|
|
&Normal
|
|
|
|
|
Always on &bottom
|
|
|
|
|
---
|
|
|
|
|
+ &Close
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/********** Desktop menu **********/
|
|
|
|
|
int deskNum = KWindowSystem::numberOfDesktops();
|
|
|
|
|
if (deskNum > 1)
|
|
|
|
|
{
|
|
|
|
|
int winDesk = KWindowInfo(mWindow, NET::WMDesktop).desktop();
|
|
|
|
|
QMenu* deskMenu = menu->addMenu(tr("To &Desktop"));
|
|
|
|
|
|
|
|
|
|
a = deskMenu->addAction(tr("&All Desktops"));
|
|
|
|
|
a->setData(NET::OnAllDesktops);
|
|
|
|
|
a->setEnabled(winDesk != NET::OnAllDesktops);
|
|
|
|
|
connect(a, SIGNAL(triggered(bool)), this, SLOT(moveApplicationToDesktop()));
|
|
|
|
|
deskMenu->addSeparator();
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < deskNum; ++i)
|
|
|
|
|
{
|
|
|
|
|
a = deskMenu->addAction(tr("Desktop &%1").arg(i + 1));
|
|
|
|
|
a->setData(i + 1);
|
|
|
|
|
a->setEnabled(i + 1 != winDesk);
|
|
|
|
|
connect(a, SIGNAL(triggered(bool)), this, SLOT(moveApplicationToDesktop()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int curDesk = KWindowSystem::currentDesktop();
|
|
|
|
|
a = menu->addAction(tr("&To Current Desktop"));
|
|
|
|
|
a->setData(curDesk);
|
|
|
|
|
a->setEnabled(curDesk != winDesk);
|
|
|
|
|
connect(a, SIGNAL(triggered(bool)), this, SLOT(moveApplicationToDesktop()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/********** Move/Resize **********/
|
|
|
|
|
menu->addSeparator();
|
|
|
|
|
a = menu->addAction(tr("&Move"));
|
|
|
|
|
a->setEnabled(info.actionSupported(NET::ActionMove) && !(state & NET::Max) && !(state & NET::FullScreen));
|
|
|
|
|
connect(a, &QAction::triggered, this, &UKUITaskButton::moveApplication);
|
|
|
|
|
a = menu->addAction(tr("Resi&ze"));
|
|
|
|
|
a->setEnabled(info.actionSupported(NET::ActionResize) && !(state & NET::Max) && !(state & NET::FullScreen));
|
|
|
|
|
connect(a, &QAction::triggered, this, &UKUITaskButton::resizeApplication);
|
|
|
|
|
|
|
|
|
|
/********** State menu **********/
|
|
|
|
|
menu->addSeparator();
|
|
|
|
|
|
|
|
|
|
a = menu->addAction(tr("Ma&ximize"));
|
|
|
|
|
a->setEnabled(info.actionSupported(NET::ActionMax) && (!(state & NET::Max) || (state & NET::Hidden)));
|
|
|
|
|
a->setData(NET::Max);
|
|
|
|
|
connect(a, SIGNAL(triggered(bool)), this, SLOT(maximizeApplication()));
|
|
|
|
|
|
|
|
|
|
if (event->modifiers() & Qt::ShiftModifier)
|
|
|
|
|
{
|
|
|
|
|
a = menu->addAction(tr("Maximize vertically"));
|
|
|
|
|
a->setEnabled(info.actionSupported(NET::ActionMaxVert) && !((state & NET::MaxVert) || (state & NET::Hidden)));
|
|
|
|
|
a->setData(NET::MaxVert);
|
|
|
|
|
connect(a, SIGNAL(triggered(bool)), this, SLOT(maximizeApplication()));
|
|
|
|
|
|
|
|
|
|
a = menu->addAction(tr("Maximize horizontally"));
|
|
|
|
|
a->setEnabled(info.actionSupported(NET::ActionMaxHoriz) && !((state & NET::MaxHoriz) || (state & NET::Hidden)));
|
|
|
|
|
a->setData(NET::MaxHoriz);
|
|
|
|
|
connect(a, SIGNAL(triggered(bool)), this, SLOT(maximizeApplication()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
a = menu->addAction(tr("&Restore"));
|
|
|
|
|
a->setEnabled((state & NET::Hidden) || (state & NET::Max) || (state & NET::MaxHoriz) || (state & NET::MaxVert));
|
|
|
|
|
connect(a, SIGNAL(triggered(bool)), this, SLOT(deMaximizeApplication()));
|
|
|
|
|
|
|
|
|
|
a = menu->addAction(tr("Mi&nimize"));
|
|
|
|
|
a->setEnabled(info.actionSupported(NET::ActionMinimize) && !(state & NET::Hidden));
|
|
|
|
|
connect(a, SIGNAL(triggered(bool)), this, SLOT(minimizeApplication()));
|
|
|
|
|
|
|
|
|
|
if (state & NET::Shaded)
|
|
|
|
|
{
|
|
|
|
|
a = menu->addAction(tr("Roll down"));
|
|
|
|
|
a->setEnabled(info.actionSupported(NET::ActionShade) && !(state & NET::Hidden));
|
|
|
|
|
connect(a, SIGNAL(triggered(bool)), this, SLOT(unShadeApplication()));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
a = menu->addAction(tr("Roll up"));
|
|
|
|
|
a->setEnabled(info.actionSupported(NET::ActionShade) && !(state & NET::Hidden));
|
|
|
|
|
connect(a, SIGNAL(triggered(bool)), this, SLOT(shadeApplication()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/********** Layer menu **********/
|
|
|
|
|
menu->addSeparator();
|
|
|
|
|
|
|
|
|
|
QMenu* layerMenu = menu->addMenu(tr("&Layer"));
|
|
|
|
|
|
|
|
|
|
a = layerMenu->addAction(tr("Always on &top"));
|
|
|
|
|
// FIXME: There is no info.actionSupported(NET::ActionKeepAbove)
|
|
|
|
|
a->setEnabled(!(state & NET::KeepAbove));
|
|
|
|
|
a->setData(NET::KeepAbove);
|
|
|
|
|
connect(a, SIGNAL(triggered(bool)), this, SLOT(setApplicationLayer()));
|
|
|
|
|
|
|
|
|
|
a = layerMenu->addAction(tr("&Normal"));
|
|
|
|
|
a->setEnabled((state & NET::KeepAbove) || (state & NET::KeepBelow));
|
|
|
|
|
// FIXME: There is no NET::KeepNormal, so passing 0
|
|
|
|
|
a->setData(0);
|
|
|
|
|
connect(a, SIGNAL(triggered(bool)), this, SLOT(setApplicationLayer()));
|
|
|
|
|
|
|
|
|
|
a = layerMenu->addAction(tr("Always on &bottom"));
|
|
|
|
|
// FIXME: There is no info.actionSupported(NET::ActionKeepBelow)
|
|
|
|
|
a->setEnabled(!(state & NET::KeepBelow));
|
|
|
|
|
a->setData(NET::KeepBelow);
|
|
|
|
|
connect(a, SIGNAL(triggered(bool)), this, SLOT(setApplicationLayer()));
|
|
|
|
|
|
|
|
|
|
/********** Kill menu **********/
|
|
|
|
|
menu->addSeparator();
|
2020-08-17 14:43:42 +08:00
|
|
|
a = menu->addAction(QIcon::fromTheme("process-stop"), tr("&Close"));
|
2020-01-17 17:23:40 +08:00
|
|
|
connect(a, SIGNAL(triggered(bool)), this, SLOT(closeApplication()));
|
|
|
|
|
menu->setGeometry(mParentTaskBar->panel()->calculatePopupWindowPos(mapToGlobal(event->pos()), menu->sizeHint()));
|
|
|
|
|
mPlugin->willShowWindow(menu);
|
|
|
|
|
menu->show();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
|
|
|
|
|
|
************************************************/
|
|
|
|
|
void UKUITaskButton::setUrgencyHint(bool set)
|
|
|
|
|
{
|
|
|
|
|
if (mUrgencyHint == set)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (!set)
|
|
|
|
|
KWindowSystem::demandAttention(mWindow, false);
|
|
|
|
|
|
|
|
|
|
mUrgencyHint = set;
|
|
|
|
|
setProperty("urgent", set);
|
|
|
|
|
style()->unpolish(this);
|
|
|
|
|
style()->polish(this);
|
|
|
|
|
update();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool UKUITaskButton::isOnDesktop(int desktop) const
|
|
|
|
|
{
|
|
|
|
|
return KWindowInfo(mWindow, NET::WMDesktop).isOnDesktop(desktop);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool UKUITaskButton::isOnCurrentScreen() const
|
|
|
|
|
{
|
|
|
|
|
return QApplication::desktop()->screenGeometry(parentTaskBar()).intersects(KWindowInfo(mWindow, NET::WMFrameExtents).frameGeometry());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool UKUITaskButton::isMinimized() const
|
|
|
|
|
{
|
|
|
|
|
return KWindowInfo(mWindow,NET::WMState | NET::XAWMState).isMinimized();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Qt::Corner UKUITaskButton::origin() const
|
|
|
|
|
{
|
|
|
|
|
return mOrigin;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UKUITaskButton::setOrigin(Qt::Corner newOrigin)
|
|
|
|
|
{
|
|
|
|
|
if (mOrigin != newOrigin)
|
|
|
|
|
{
|
|
|
|
|
mOrigin = newOrigin;
|
|
|
|
|
update();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UKUITaskButton::setAutoRotation(bool value, IUKUIPanel::Position position)
|
|
|
|
|
{
|
|
|
|
|
if (value)
|
|
|
|
|
{
|
|
|
|
|
switch (position)
|
|
|
|
|
{
|
|
|
|
|
case IUKUIPanel::PositionTop:
|
|
|
|
|
case IUKUIPanel::PositionBottom:
|
|
|
|
|
setOrigin(Qt::TopLeftCorner);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case IUKUIPanel::PositionLeft:
|
|
|
|
|
setOrigin(Qt::BottomLeftCorner);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case IUKUIPanel::PositionRight:
|
|
|
|
|
setOrigin(Qt::TopRightCorner);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
setOrigin(Qt::TopLeftCorner);
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-01 22:46:04 +08:00
|
|
|
void UKUITaskButton::enterEvent(QEvent *)
|
|
|
|
|
{
|
|
|
|
|
taskbuttonstatus=HOVER;
|
|
|
|
|
update();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UKUITaskButton::leaveEvent(QEvent *)
|
|
|
|
|
{
|
|
|
|
|
taskbuttonstatus=NORMAL;
|
|
|
|
|
update();
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-10 20:17:51 +08:00
|
|
|
/*在paintEvent中执行绘图事件会造成高分屏下图片模糊
|
|
|
|
|
* 高分屏的图片模糊问题大概率与svg/png图片无关
|
|
|
|
|
* */
|
2020-01-17 17:23:40 +08:00
|
|
|
void UKUITaskButton::paintEvent(QPaintEvent *event)
|
|
|
|
|
{
|
2020-06-10 20:17:51 +08:00
|
|
|
QToolButton::paintEvent(event);
|
|
|
|
|
return;
|
|
|
|
|
/*
|
2020-01-17 17:23:40 +08:00
|
|
|
QSize sz = size();
|
2020-05-28 09:16:40 +08:00
|
|
|
QSize adjSz =sz;
|
2020-01-17 17:23:40 +08:00
|
|
|
QTransform transform;
|
|
|
|
|
QPoint originPoint;
|
|
|
|
|
|
2020-06-10 20:17:51 +08:00
|
|
|
switch (mOrigin)
|
|
|
|
|
{
|
|
|
|
|
case Qt::TopLeftCorner:
|
|
|
|
|
transform.rotate(0.0);
|
|
|
|
|
originPoint = QPoint(0.0, 0.0);
|
|
|
|
|
break;
|
2020-01-17 17:23:40 +08:00
|
|
|
|
2020-06-10 20:17:51 +08:00
|
|
|
case Qt::TopRightCorner:
|
|
|
|
|
transform.rotate(90.0);
|
|
|
|
|
originPoint = QPoint(0.0, -sz.width());
|
|
|
|
|
adjSz.transpose();
|
|
|
|
|
break;
|
2020-01-17 17:23:40 +08:00
|
|
|
|
2020-06-10 20:17:51 +08:00
|
|
|
case Qt::BottomRightCorner:
|
|
|
|
|
transform.rotate(180.0);
|
|
|
|
|
originPoint = QPoint(-sz.width(), -sz.height());
|
|
|
|
|
break;
|
2020-01-17 17:23:40 +08:00
|
|
|
|
2020-06-10 20:17:51 +08:00
|
|
|
case Qt::BottomLeftCorner:
|
|
|
|
|
transform.rotate(270.0);
|
|
|
|
|
originPoint = QPoint(-sz.height(), 0.0);
|
|
|
|
|
adjSz.transpose();
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-01-17 17:23:40 +08:00
|
|
|
|
|
|
|
|
bool drawPixmapNextTime = false;
|
|
|
|
|
|
|
|
|
|
if (!mDrawPixmap)
|
|
|
|
|
{
|
|
|
|
|
mPixmap = QPixmap(adjSz);
|
2020-03-01 22:46:04 +08:00
|
|
|
mPixmap.fill(QColor(255, 0, 0, 0));
|
2020-01-17 17:23:40 +08:00
|
|
|
|
|
|
|
|
if (adjSz != sz)
|
|
|
|
|
resize(adjSz); // this causes paint event to be repeated - next time we'll paint the pixmap to the widget surface.
|
|
|
|
|
|
|
|
|
|
// copied from QToolButton::paintEvent {
|
|
|
|
|
QStylePainter painter(&mPixmap, this);
|
|
|
|
|
QStyleOptionToolButton opt;
|
|
|
|
|
initStyleOption(&opt);
|
2020-03-01 22:46:04 +08:00
|
|
|
painter.setBrush(QBrush(QColor(0xFF,0xFF,0xFF,0x19)));
|
2020-01-17 17:23:40 +08:00
|
|
|
painter.drawComplexControl(QStyle::CC_ToolButton, opt);
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
if (adjSz != sz)
|
|
|
|
|
{
|
|
|
|
|
resize(sz);
|
|
|
|
|
drawPixmapNextTime = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
mDrawPixmap = true; // transfer the pixmap to the widget now!
|
|
|
|
|
}
|
|
|
|
|
if (mDrawPixmap)
|
|
|
|
|
{
|
|
|
|
|
QPainter painter(this);
|
|
|
|
|
painter.setTransform(transform);
|
|
|
|
|
painter.drawPixmap(originPoint, mPixmap);
|
|
|
|
|
|
|
|
|
|
drawPixmapNextTime = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mDrawPixmap = drawPixmapNextTime;
|
2020-06-10 20:17:51 +08:00
|
|
|
*/
|
2020-01-17 17:23:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool UKUITaskButton::hasDragAndDropHover() const
|
|
|
|
|
{
|
|
|
|
|
return mDNDTimer->isActive();
|
|
|
|
|
}
|