File indexing completed on 2024-07-21 12:15:32

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 1999 Matthias Ettrich <ettrich@kde.org>
0004     SPDX-FileCopyrightText: 2007 Lubos Lunak <l.lunak@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.1-or-later
0007 */
0008 
0009 #include "kx11extras.h"
0010 
0011 #include "kwindowsystem.h"
0012 #include "kwindowsystem_p.h"
0013 
0014 #include "kxutils_p.h"
0015 #include "netwm.h"
0016 
0017 #include <QGuiApplication>
0018 #include <QRect>
0019 
0020 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
0021 #include <private/qtx11extras_p.h>
0022 #else
0023 #include <QX11Info>
0024 #endif
0025 
0026 // QPoint and QSize all have handy / operators which are useful for scaling, positions and sizes for high DPI support
0027 // QRect does not, so we create one for internal purposes within this class
0028 inline QRect operator/(const QRect &rectangle, qreal factor)
0029 {
0030     return QRect(rectangle.topLeft() / factor, rectangle.size() / factor);
0031 }
0032 
0033 KX11Extras *KX11Extras::self()
0034 {
0035     static KX11Extras instance;
0036     return &instance;
0037 }
0038 
0039 QList<WId> KX11Extras::windows()
0040 {
0041     return KWindowSystem::d_func()->windows();
0042 }
0043 
0044 bool KX11Extras::hasWId(WId w)
0045 {
0046     return windows().contains(w);
0047 }
0048 
0049 QList<WId> KX11Extras::stackingOrder()
0050 {
0051     return KWindowSystem::d_func()->stackingOrder();
0052 }
0053 
0054 WId KX11Extras::activeWindow()
0055 {
0056     return KWindowSystem::d_func()->activeWindow();
0057 }
0058 
0059 void KX11Extras::activateWindow(WId win, long time)
0060 {
0061     KWindowSystem::d_func()->activateWindow(win, time);
0062 }
0063 
0064 void KX11Extras::forceActiveWindow(WId win, long time)
0065 {
0066     KWindowSystem::d_func()->forceActiveWindow(win, time);
0067 }
0068 
0069 bool KX11Extras::compositingActive()
0070 {
0071     return KWindowSystem::d_func()->compositingActive();
0072 }
0073 
0074 int KX11Extras::currentDesktop()
0075 {
0076     return KWindowSystem::d_func()->currentDesktop();
0077 }
0078 
0079 int KX11Extras::numberOfDesktops()
0080 {
0081     return KWindowSystem::d_func()->numberOfDesktops();
0082 }
0083 
0084 void KX11Extras::setCurrentDesktop(int desktop)
0085 {
0086     KWindowSystem::d_func()->setCurrentDesktop(desktop);
0087 }
0088 
0089 void KX11Extras::setOnAllDesktops(WId win, bool b)
0090 {
0091     KWindowSystem::d_func()->setOnAllDesktops(win, b);
0092 }
0093 
0094 void KX11Extras::setOnDesktop(WId win, int desktop)
0095 {
0096     KWindowSystem::d_func()->setOnDesktop(win, desktop);
0097 }
0098 
0099 void KX11Extras::setOnActivities(WId win, const QStringList &activities)
0100 {
0101     KWindowSystem::d_func()->setOnActivities(win, activities);
0102 }
0103 
0104 QPixmap KX11Extras::icon(WId win, int width, int height, bool scale)
0105 {
0106     return icon(win, width, height, scale, NETWM | WMHints | ClassHint | XApp);
0107 }
0108 
0109 QPixmap KX11Extras::icon(WId win, int width, int height, bool scale, int flags)
0110 {
0111     return KWindowSystem::d_func()->icon(win, width, height, scale, flags);
0112 }
0113 
0114 QPixmap iconFromNetWinInfo(int width, int height, bool scale, int flags, NETWinInfo *info)
0115 {
0116     QPixmap result;
0117     if (!info) {
0118         return result;
0119     }
0120     if (flags & KX11Extras::NETWM) {
0121         NETIcon ni = info->icon(width, height);
0122         if (ni.data && ni.size.width > 0 && ni.size.height > 0) {
0123             QImage img((uchar *)ni.data, (int)ni.size.width, (int)ni.size.height, QImage::Format_ARGB32);
0124             if (scale && width > 0 && height > 0 && img.size() != QSize(width, height) && !img.isNull()) {
0125                 img = img.scaled(width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
0126             }
0127             if (!img.isNull()) {
0128                 result = QPixmap::fromImage(img);
0129             }
0130             return result;
0131         }
0132     }
0133 
0134     if (flags & KX11Extras::WMHints) {
0135         xcb_pixmap_t p = info->icccmIconPixmap();
0136         xcb_pixmap_t p_mask = info->icccmIconPixmapMask();
0137 
0138         if (p != XCB_PIXMAP_NONE) {
0139             QPixmap pm = KXUtils::createPixmapFromHandle(info->xcbConnection(), p, p_mask);
0140             if (scale && width > 0 && height > 0 && !pm.isNull() //
0141                 && (pm.width() != width || pm.height() != height)) {
0142                 result = QPixmap::fromImage(pm.toImage().scaled(width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
0143             } else {
0144                 result = pm;
0145             }
0146         }
0147     }
0148 
0149     // Since width can be any arbitrary size, but the icons cannot,
0150     // take the nearest value for best results (ignoring 22 pixel
0151     // icons as they don't exist for apps):
0152     int iconWidth;
0153     if (width < 24) {
0154         iconWidth = 16;
0155     } else if (width < 40) {
0156         iconWidth = 32;
0157     } else if (width < 56) {
0158         iconWidth = 48;
0159     } else if (width < 96) {
0160         iconWidth = 64;
0161     } else if (width < 192) {
0162         iconWidth = 128;
0163     } else {
0164         iconWidth = 256;
0165     }
0166 
0167     if (flags & KX11Extras::ClassHint) {
0168         // Try to load the icon from the classhint if the app didn't specify
0169         // its own:
0170         if (result.isNull()) {
0171             const QIcon icon = QIcon::fromTheme(QString::fromUtf8(info->windowClassClass()).toLower());
0172             const QPixmap pm = icon.isNull() ? QPixmap() : icon.pixmap(iconWidth, iconWidth);
0173             if (scale && !pm.isNull()) {
0174                 result = QPixmap::fromImage(pm.toImage().scaled(width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
0175             } else {
0176                 result = pm;
0177             }
0178         }
0179     }
0180 
0181     if (flags & KX11Extras::XApp) {
0182         // If the icon is still a null pixmap, load the icon for X applications
0183         // as a last resort:
0184         if (result.isNull()) {
0185             const QIcon icon = QIcon::fromTheme(QStringLiteral("xorg"));
0186             const QPixmap pm = icon.isNull() ? QPixmap() : icon.pixmap(iconWidth, iconWidth);
0187             if (scale && !pm.isNull()) {
0188                 result = QPixmap::fromImage(pm.toImage().scaled(width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
0189             } else {
0190                 result = pm;
0191             }
0192         }
0193     }
0194     return result;
0195 }
0196 
0197 QPixmap KX11Extras::icon(WId win, int width, int height, bool scale, int flags, NETWinInfo *info)
0198 {
0199     width *= qGuiApp->devicePixelRatio();
0200     height *= qGuiApp->devicePixelRatio();
0201 
0202     if (info) {
0203         return iconFromNetWinInfo(width, height, scale, flags, info);
0204     }
0205 
0206     NETWinInfo newInfo(QX11Info::connection(), win, QX11Info::appRootWindow(), NET::WMIcon, NET::WM2WindowClass | NET::WM2IconPixmap);
0207 
0208     return iconFromNetWinInfo(width, height, scale, flags, &newInfo);
0209 }
0210 
0211 void KX11Extras::minimizeWindow(WId win)
0212 {
0213     KWindowSystem::d_func()->minimizeWindow(win);
0214 }
0215 
0216 void KX11Extras::unminimizeWindow(WId win)
0217 {
0218     KWindowSystem::d_func()->unminimizeWindow(win);
0219 }
0220 
0221 QRect KX11Extras::workArea(int desktop)
0222 {
0223     return KWindowSystem::d_func()->workArea(desktop) / qApp->devicePixelRatio();
0224 }
0225 
0226 QRect KX11Extras::workArea(const QList<WId> &exclude, int desktop)
0227 {
0228     return KWindowSystem::d_func()->workArea(exclude, desktop) / qApp->devicePixelRatio();
0229 }
0230 
0231 QString KX11Extras::desktopName(int desktop)
0232 {
0233     return KWindowSystem::d_func()->desktopName(desktop);
0234 }
0235 
0236 void KX11Extras::setDesktopName(int desktop, const QString &name)
0237 {
0238     KWindowSystem::d_func()->setDesktopName(desktop, name);
0239 }
0240 
0241 QString KX11Extras::readNameProperty(WId win, unsigned long atom)
0242 {
0243     return KWindowSystem::d_func()->readNameProperty(win, atom);
0244 }
0245 
0246 bool KX11Extras::mapViewport()
0247 {
0248     return KWindowSystem::d_func()->mapViewport();
0249 }
0250 
0251 void KX11Extras::setExtendedStrut(WId win,
0252                                   int left_width,
0253                                   int left_start,
0254                                   int left_end,
0255                                   int right_width,
0256                                   int right_start,
0257                                   int right_end,
0258                                   int top_width,
0259                                   int top_start,
0260                                   int top_end,
0261                                   int bottom_width,
0262                                   int bottom_start,
0263                                   int bottom_end)
0264 {
0265     const qreal dpr = qApp->devicePixelRatio();
0266     KWindowSystem::d_func()->setExtendedStrut(win,
0267                                               left_width * dpr,
0268                                               left_start * dpr,
0269                                               left_end * dpr,
0270                                               right_width * dpr,
0271                                               right_start * dpr,
0272                                               right_end * dpr,
0273                                               top_width * dpr,
0274                                               top_start * dpr,
0275                                               top_end * dpr,
0276                                               bottom_width * dpr,
0277                                               bottom_start * dpr,
0278                                               bottom_end * dpr);
0279 }
0280 
0281 void KX11Extras::setStrut(WId win, int left, int right, int top, int bottom)
0282 {
0283     const qreal dpr = qApp->devicePixelRatio();
0284     KWindowSystem::d_func()->setStrut(win, left * dpr, right * dpr, top * dpr, bottom * dpr);
0285 }
0286 
0287 void KX11Extras::connectNotify(const QMetaMethod &signal)
0288 {
0289     KWindowSystem::self()->d_func()->connectNotify(signal);
0290     QObject::connectNotify(signal);
0291 }
0292 
0293 #include "moc_kx11extras.cpp"