File indexing completed on 2024-03-24 05:49:31
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 //--------------------------------------------------------------------------------