File indexing completed on 2024-04-21 11:38:03

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 2008 Carlo Segato <brandon.ml@gmail.com>
0004     SPDX-FileCopyrightText: 2011 Pau Garcia i Quiles <pgquiles@elpauer.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.1-or-later
0007 */
0008 
0009 #include "kwindowinfo.h"
0010 #include "kwindowsystem.h"
0011 #include <QCoreApplication>
0012 #include <stdlib.h>
0013 #include <windows.h>
0014 
0015 class Q_DECL_HIDDEN KWindowInfo::Private
0016 {
0017 public:
0018     Private()
0019         : properties(0)
0020         , properties2(0)
0021     {
0022     }
0023 
0024     ~Private()
0025     {
0026     }
0027 
0028     HWND win_;
0029     int ref;
0030     unsigned long properties;
0031     unsigned long properties2;
0032 
0033 private:
0034     Private(const Private &);
0035     void operator=(const Private &);
0036 };
0037 
0038 #include <QRect>
0039 
0040 KWindowInfo::KWindowInfo(WId win, unsigned long properties, unsigned long properties2)
0041     : d(new Private)
0042 {
0043     d->ref = 1;
0044     d->win_ = reinterpret_cast<HWND>(win);
0045     d->properties = properties;
0046     d->properties2 = properties2;
0047 }
0048 
0049 KWindowInfo::KWindowInfo()
0050     : d(nullptr)
0051 {
0052 }
0053 
0054 KWindowInfo::~KWindowInfo()
0055 {
0056     if (d != nullptr) {
0057         if (--d->ref == 0) {
0058             delete d;
0059         }
0060     }
0061 }
0062 
0063 KWindowInfo::KWindowInfo(const KWindowInfo &wininfo)
0064     : d(wininfo.d)
0065 {
0066     if (d != nullptr) {
0067         ++d->ref;
0068     }
0069 }
0070 
0071 KWindowInfo &KWindowInfo::operator=(const KWindowInfo &wininfo)
0072 {
0073     if (d != wininfo.d) {
0074         if (d != nullptr)
0075             if (--d->ref == 0) {
0076                 delete d;
0077             }
0078         d = wininfo.d;
0079         if (d != nullptr) {
0080             ++d->ref;
0081         }
0082     }
0083     return *this;
0084 }
0085 
0086 bool KWindowInfo::valid(bool withdrawn_is_valid) const
0087 {
0088     return true;
0089 }
0090 
0091 WId KWindowInfo::win() const
0092 {
0093     return reinterpret_cast<WId>(d->win_);
0094 }
0095 
0096 unsigned long KWindowInfo::state() const
0097 {
0098     unsigned long state = 0;
0099 #ifndef _WIN32_WCE
0100     if (IsZoomed(d->win_)) {
0101         state |= NET::Max;
0102     }
0103 #endif
0104     if (!IsWindowVisible(d->win_)) {
0105         state |= NET::Hidden;
0106     }
0107 
0108 #ifndef _WIN32_WCE
0109     LONG_PTR lp = GetWindowLongPtr(d->win_, GWL_EXSTYLE);
0110     if (lp & WS_EX_TOOLWINDOW) {
0111         state |= NET::SkipTaskbar;
0112     }
0113 #endif
0114 
0115     return state;
0116 }
0117 
0118 bool KWindowInfo::hasState(unsigned long s) const
0119 {
0120     return (state() & s);
0121 }
0122 
0123 bool KWindowInfo::isMinimized() const
0124 {
0125 #ifndef _WIN32_WCE
0126     return IsIconic(d->win_);
0127 #else
0128     return false;
0129 #endif
0130 }
0131 
0132 NET::MappingState KWindowInfo::mappingState() const
0133 {
0134 #ifndef _WIN32_WCE
0135     if (IsIconic(d->win_)) {
0136         return NET::Iconic;
0137     }
0138 #endif
0139     if (!IsWindowVisible(d->win_)) {
0140         return NET::Withdrawn;
0141     }
0142     return NET::Visible;
0143 }
0144 
0145 NETExtendedStrut KWindowInfo::extendedStrut() const
0146 {
0147     return NETExtendedStrut();
0148 }
0149 
0150 NET::WindowType KWindowInfo::windowType(int supported_types) const
0151 {
0152     NET::WindowType wt(NET::Normal);
0153 
0154     long windowStyle = GetWindowLong(d->win_, GWL_STYLE);
0155     long windowStyleEx = GetWindowLong(d->win_, GWL_EXSTYLE);
0156 
0157     if (windowStyle & WS_POPUP && supported_types & NET::PopupMenuMask) {
0158         return NET::PopupMenu;
0159     } else if (windowStyleEx & WS_EX_TOOLWINDOW && supported_types & NET::TooltipMask) {
0160         return NET::Tooltip;
0161     } else if (!(windowStyle & WS_CHILD) && supported_types & NET::NormalMask) {
0162         return NET::Normal;
0163     }
0164 
0165     return wt;
0166 }
0167 
0168 QString KWindowInfo::visibleNameWithState() const
0169 {
0170     QString s = visibleName();
0171     if (isMinimized()) {
0172         s.prepend(QLatin1Char('('));
0173         s.append(QLatin1Char(')'));
0174     }
0175     return s;
0176 }
0177 
0178 QString KWindowInfo::visibleName() const
0179 {
0180     return name();
0181 }
0182 
0183 QString KWindowInfo::name() const
0184 {
0185     QByteArray windowText = QByteArray((GetWindowTextLength(d->win_) + 1) * sizeof(wchar_t), 0);
0186     GetWindowTextW(d->win_, (LPWSTR)windowText.data(), windowText.size());
0187     return QString::fromWCharArray((wchar_t *)windowText.data());
0188 }
0189 
0190 QString KWindowInfo::visibleIconNameWithState() const
0191 {
0192     return QString();
0193 }
0194 
0195 QString KWindowInfo::visibleIconName() const
0196 {
0197     return QString();
0198 }
0199 
0200 QString KWindowInfo::iconName() const
0201 {
0202     return QString();
0203 }
0204 
0205 bool KWindowInfo::isOnCurrentDesktop() const
0206 {
0207     return true;
0208 }
0209 
0210 bool KWindowInfo::isOnDesktop(int desk) const
0211 {
0212     return desk == desktop();
0213 }
0214 
0215 bool KWindowInfo::onAllDesktops() const
0216 {
0217     return false;
0218 }
0219 
0220 int KWindowInfo::desktop() const
0221 {
0222     return 1;
0223 }
0224 
0225 QRect KWindowInfo::geometry() const
0226 {
0227     RECT wndRect;
0228     memset(&wndRect, 0, sizeof(wndRect));
0229 
0230     // fetch the geometry INCLUDING the frames
0231     if (GetWindowRect(d->win_, &wndRect)) {
0232         QRect result;
0233         result.setCoords(wndRect.left, wndRect.top, wndRect.right, wndRect.bottom);
0234         return result;
0235     }
0236 
0237     return QRect();
0238 }
0239 
0240 QRect KWindowInfo::frameGeometry() const
0241 {
0242     RECT wndRect;
0243     memset(&wndRect, 0, sizeof(wndRect));
0244 
0245     // fetch only client area geometries ... i hope that's right
0246     if (GetClientRect(d->win_, &wndRect)) {
0247         QRect result;
0248         result.setCoords(wndRect.left, wndRect.top, wndRect.right, wndRect.bottom);
0249         return result;
0250     }
0251 
0252     return QRect();
0253 }
0254 
0255 bool KWindowInfo::actionSupported(NET::Action action) const
0256 {
0257     return true; // no idea if it's supported or not -> pretend it is
0258 }
0259 
0260 #if 0
0261 WId KWindowInfo::transientFor() const
0262 {
0263     kWarning((d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2TransientFor) == 0, 176)
0264             << "Pass NET::WM2TransientFor to KWindowInfo";
0265     return d->info->transientFor();
0266 }
0267 
0268 WId KWindowInfo::groupLeader() const
0269 {
0270     kWarning((d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2GroupLeader) == 0, 176)
0271             << "Pass NET::WM2GroupLeader to KWindowInfo";
0272     return d->info->groupLeader();
0273 }
0274 #endif
0275 
0276 QByteArray KWindowInfo::windowClassClass() const
0277 {
0278     //    kWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2WindowClass ) == 0, 176 )
0279     //        << "Pass NET::WM2WindowClass to KWindowInfo";
0280     //    return d->info->windowClassClass();
0281 
0282     // Implemented per http://tronche.com/gui/x/icccm/sec-4.html#WM_CLASS (but only 2nd and 3rd choices, -name ignored)
0283     char *resourcenamevar;
0284     resourcenamevar = getenv("RESOURCE_NAME");
0285     if (resourcenamevar != nullptr) {
0286         return QByteArray(resourcenamevar);
0287     }
0288 
0289     return QCoreApplication::applicationName().toLocal8Bit();
0290 }
0291 
0292 QByteArray KWindowInfo::windowClassName() const
0293 {
0294     //    kWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2WindowClass ) == 0, 176 )
0295     //        << "Pass NET::WM2WindowClass to KWindowInfo";
0296     //    return d->info->windowClassName();
0297 
0298     // Maybe should use RealGetWindowClass instead of GetClassName? See
0299     // http://blogs.msdn.com/b/oldnewthing/archive/2010/12/31/10110524.aspx
0300 
0301     const int max = 256; // truncate to 255 characters
0302     TCHAR name[max];
0303     int count = GetClassName(d->win_, name, max);
0304     return QString::fromUtf16((ushort *)name).toLocal8Bit();
0305 }
0306 
0307 #if 0
0308 QByteArray KWindowInfo::windowRole() const
0309 {
0310     kWarning((d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2WindowRole) == 0, 176)
0311             << "Pass NET::WM2WindowRole to KWindowInfo";
0312     return d->info->windowRole();
0313 }
0314 
0315 QByteArray KWindowInfo::clientMachine() const
0316 {
0317     kWarning((d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2ClientMachine) == 0, 176)
0318             << "Pass NET::WM2ClientMachine to KWindowInfo";
0319     return d->info->clientMachine();
0320 }
0321 
0322 bool KWindowInfo::actionSupported(NET::Action action) const
0323 {
0324     kWarning((d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2AllowedActions) == 0, 176)
0325             << "Pass NET::WM2AllowedActions to KWindowInfo";
0326     if (KWindowSystem::allowedActionsSupported()) {
0327         return d->info->allowedActions() & action;
0328     } else {
0329         return true;    // no idea if it's supported or not -> pretend it is
0330     }
0331 }
0332 #endif