File indexing completed on 2024-04-14 15:49:50

0001 // SPDX-License-Identifier: GPL-3.0-or-later
0002 /*
0003   Copyright 2017, 2018, 2019 Martin Koller, kollix@aon.at
0004 
0005   This file is part of liquidshell.
0006 
0007   liquidshell is free software: you can redistribute it and/or modify
0008   it under the terms of the GNU General Public License as published by
0009   the Free Software Foundation, either version 3 of the License, or
0010   (at your option) any later version.
0011 
0012   liquidshell is distributed in the hope that it will be useful,
0013   but WITHOUT ANY WARRANTY; without even the implied warranty of
0014   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0015   GNU General Public License for more details.
0016 
0017   You should have received a copy of the GNU General Public License
0018   along with liquidshell.  If not, see <http://www.gnu.org/licenses/>.
0019 */
0020 
0021 #include <TaskBarButton.hxx>
0022 #include <KWinCompat.hxx>
0023 
0024 #include <QHBoxLayout>
0025 #include <QLabel>
0026 #include <QDebug>
0027 #include <QMouseEvent>
0028 #include <QStyle>
0029 #include <QStyleOptionButton>
0030 #include <QPainter>
0031 #include <QX11Info>
0032 #include <QMenu>
0033 #include <QDragEnterEvent>
0034 #include <QDragLeaveEvent>
0035 #include <QDrag>
0036 #include <QMimeData>
0037 #include <QGuiApplication>
0038 #include <QStyleHints>
0039 #include <QPointer>
0040 
0041 #include <KSqueezedTextLabel>
0042 #include <KColorScheme>
0043 #include <KLocalizedString>
0044 
0045 #include <netwm.h>
0046 
0047 //--------------------------------------------------------------------------------
0048 
0049 TaskBarButton::TaskBarButton(WId theWid)
0050   : wid(theWid)
0051 {
0052   setAutoFillBackground(true);
0053   setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
0054   setAcceptDrops(true);
0055   dragDropTimer.setSingleShot(true);
0056   dragDropTimer.setInterval(1000);
0057   connect(&dragDropTimer, &QTimer::timeout,
0058           [this]() { KWindowSystem::raiseWindow(wid); KWinCompat::forceActiveWindow(wid); });
0059 
0060   QHBoxLayout *hbox = new QHBoxLayout(this);
0061   hbox->setContentsMargins(QMargins(4, 2, 4, 2));
0062 
0063   iconLabel = new QLabel;
0064   iconLabel->setScaledContents(true);
0065   iconLabel->setFixedSize(32, 32);
0066   iconLabel->setContextMenuPolicy(Qt::PreventContextMenu);
0067   hbox->addWidget(iconLabel);
0068 
0069   textLabel = new KSqueezedTextLabel;
0070   textLabel->setTextElideMode(Qt::ElideRight);
0071   textLabel->setContextMenuPolicy(Qt::PreventContextMenu);
0072   hbox->addWidget(textLabel);
0073 
0074   fill();
0075   setBackground();
0076 
0077   connect(KWindowSystem::self(), SIGNAL(windowChanged(WId, NET::Properties, NET::Properties2)),
0078           this, SLOT(windowChanged(WId, NET::Properties, NET::Properties2)));
0079 
0080   connect(KWinCompat::self(), &KWinCompat::activeWindowChanged,
0081           this, &TaskBarButton::setBackground);
0082 }
0083 
0084 //--------------------------------------------------------------------------------
0085 
0086 void TaskBarButton::setIconSize(int size)
0087 {
0088   iconLabel->setFixedSize(size, size);
0089 }
0090 
0091 //--------------------------------------------------------------------------------
0092 
0093 void TaskBarButton::fill()
0094 {
0095   KWindowInfo win(wid, NET::WMName | NET::WMIcon);
0096   iconLabel->setPixmap(KWinCompat::icon(wid, 32, 32, true));
0097   textLabel->setText(win.name());
0098   setToolTip(win.name());
0099 }
0100 
0101 //--------------------------------------------------------------------------------
0102 
0103 void TaskBarButton::mousePressEvent(QMouseEvent *event)
0104 {
0105   if ( event->button() == Qt::LeftButton )
0106   {
0107     KWindowSystem::setShowingDesktop(false);
0108 
0109     if ( wid == KWinCompat::activeWindow() )
0110       KWinCompat::minimizeWindow(wid);
0111     else
0112       KWinCompat::forceActiveWindow(wid);
0113 
0114     dragStartPos = event->pos();
0115     event->accept();
0116   }
0117   else if ( event->button() == Qt::RightButton )
0118   {
0119     // context menu to close window etc.
0120     QPointer<QMenu> menu(new QMenu(this));
0121 
0122     if ( KWinCompat::numberOfDesktops() > 1 )
0123     {
0124       QMenu *desktops = menu->addMenu(i18n("Move To Desktop"));
0125       desktops->addAction(i18n("All Desktops"), [this]() { KWinCompat::setOnAllDesktops(wid, true); });
0126       desktops->addSeparator();
0127 
0128       for (int i = 1; i <= KWinCompat::numberOfDesktops(); i++)
0129         desktops->addAction(KWinCompat::desktopName(i), [this, i]() { KWinCompat::setOnDesktop(wid, i); });
0130     }
0131 
0132     menu->addAction(QIcon::fromTheme("window-close"), i18n("Close"),
0133                     [this]()
0134                     {
0135                       NETRootInfo ri(QX11Info::connection(), NET::CloseWindow);
0136                       ri.closeWindowRequest(wid);
0137                     }
0138                    );
0139 
0140     menu->exec(event->globalPos());
0141     delete menu;
0142   }
0143 }
0144 
0145 //--------------------------------------------------------------------------------
0146 
0147 void TaskBarButton::mouseMoveEvent(QMouseEvent *event)
0148 {
0149   event->accept();
0150 
0151   if ( (event->buttons() == Qt::LeftButton) &&
0152        (event->pos() - dragStartPos).manhattanLength() > QGuiApplication::styleHints()->startDragDistance() )
0153   {
0154     QDrag *drag = new QDrag(parentWidget());
0155     QMimeData *mimeData = new QMimeData;
0156     mimeData->setData("application/x-winId", QByteArray::number(static_cast<int>(wid)));
0157     drag->setMimeData(mimeData);
0158 #if QT_VERSION >= QT_VERSION_CHECK(5,15,0)
0159     drag->setPixmap(iconLabel->pixmap(Qt::ReturnByValue));
0160 #else
0161     drag->setPixmap(*(iconLabel->pixmap()));
0162 #endif
0163     drag->exec();
0164   }
0165 }
0166 
0167 //--------------------------------------------------------------------------------
0168 
0169 void TaskBarButton::paintEvent(QPaintEvent *event)
0170 {
0171   Q_UNUSED(event);
0172 
0173   QPainter painter(this);
0174 
0175   QStyleOptionButton option;
0176   initStyleOption(&option);
0177 
0178   style()->drawControl(QStyle::CE_PushButtonBevel, &option, &painter, this);
0179 }
0180 
0181 //--------------------------------------------------------------------------------
0182 
0183 void TaskBarButton::windowChanged(WId id, NET::Properties props, NET::Properties2 props2)
0184 {
0185   Q_UNUSED(id)
0186   Q_UNUSED(props2)
0187 
0188   //qDebug() << textLabel->text() << props << (props & (NET::WMVisibleName | NET::WMState |  NET::WMName));
0189   //qDebug() << this << id << props << "me" << (wid == id);
0190   //if ( (id != wid) || (props == 0) )
0191     //return;
0192 
0193   if ( props & (NET::WMState | NET::ActiveWindow) )
0194     setBackground();
0195 
0196   // WMVisibleName alone is not enough. WMName needed
0197   if ( (wid == id) && (props & (NET::WMIcon | NET::WMName)) )
0198     fill();
0199 }
0200 
0201 //--------------------------------------------------------------------------------
0202 
0203 void TaskBarButton::setBackground()
0204 {
0205   KColorScheme scheme(QPalette::Active, KColorScheme::Window);
0206   QPalette pal = palette();
0207 
0208   KWindowInfo win(wid, NET::WMState);
0209 
0210   if ( win.state() & NET::Hidden )
0211     pal.setBrush(foregroundRole(), scheme.foreground(KColorScheme::InactiveText));
0212   else
0213     pal.setBrush(foregroundRole(), scheme.foreground(KColorScheme::NormalText));
0214 
0215   QBrush brush;
0216 
0217   if ( win.state() & NET::DemandsAttention )
0218     brush = scheme.background(KColorScheme::ActiveBackground);
0219   else if ( wid == KWinCompat::activeWindow() )
0220     brush = scheme.shade(KColorScheme::MidShade);
0221   else
0222     brush = scheme.background();
0223 
0224   pal.setBrush(backgroundRole(), brush);
0225   setPalette(pal);
0226 }
0227 
0228 //--------------------------------------------------------------------------------
0229 
0230 void TaskBarButton::dragEnterEvent(QDragEnterEvent *event)
0231 {
0232   event->accept();
0233   dragDropTimer.start();
0234 }
0235 
0236 //--------------------------------------------------------------------------------
0237 
0238 void TaskBarButton::dragLeaveEvent(QDragLeaveEvent *event)
0239 {
0240   event->accept();
0241   dragDropTimer.stop();
0242 }
0243 
0244 //--------------------------------------------------------------------------------
0245 
0246 void TaskBarButton::dropEvent(QDropEvent *event)
0247 {
0248   event->accept();
0249   dragDropTimer.stop();
0250 }
0251 
0252 //--------------------------------------------------------------------------------
0253 
0254 void TaskBarButton::updateWMGeometry()
0255 {
0256 #if QT_VERSION >= QT_VERSION_CHECK(5,15,0)
0257   NETWinInfo info(QX11Info::connection(), wid, QX11Info::appRootWindow(), NET::Properties(), NET::Properties2());
0258 #else
0259   NETWinInfo info(QX11Info::connection(), wid, QX11Info::appRootWindow(), 0, 0);
0260 #endif
0261 
0262   NETRect rect;
0263   QPoint globalPos = mapToGlobal(QPoint(0, 0));
0264   rect.pos.x = globalPos.x();
0265   rect.pos.y = globalPos.y();
0266   rect.size.width = width();
0267   rect.size.height = height();
0268 
0269   info.setIconGeometry(rect);
0270 }
0271 
0272 //--------------------------------------------------------------------------------
0273 
0274 QSize TaskBarButton::sizeHint() const
0275 {
0276   QSize s = QPushButton::sizeHint();
0277   s.setHeight(s.height() - 2);
0278   return s;
0279 }
0280 
0281 //--------------------------------------------------------------------------------