Warning, file /frameworks/kwindowsystem/src/platforms/osx/kwindowinfo.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 2008 Marijn Kruisselbrink <m.kruisselbrink@student.tue.nl>
0004 
0005     SPDX-License-Identifier: LGPL-2.1-or-later
0006 */
0007 
0008 #include "kwindowinfo.h"
0009 #include "kwindowinfo_mac_p.h"
0010 #include "kwindowsystem.h"
0011 
0012 #include <KXErrorHandler>
0013 #include <QBitmap>
0014 #include <QDebug>
0015 #include <QDesktopWidget>
0016 #include <QDialog>
0017 #include <netwm.h>
0018 
0019 KWindowInfo::Private::Private()
0020     : ref(0)
0021     , win(0)
0022     , isLocal(false)
0023     , loadedData(false)
0024     , m_axWin(0)
0025     , parent()
0026     , m_pid(-1)
0027 {
0028 }
0029 
0030 void KWindowInfo::Private::setAxElement(const AXUIElementRef &axWin)
0031 {
0032     m_axWin = axWin;
0033     CFRetain(m_axWin);
0034 }
0035 
0036 void KWindowInfo::Private::setProcessSerialNumber(const ProcessSerialNumber &psn)
0037 {
0038     m_psn = psn;
0039     GetProcessPID(&psn, &m_pid);
0040 }
0041 
0042 KWindowInfo::Private::~Private()
0043 {
0044     if (m_axWin) {
0045         CFRelease(m_axWin);
0046     }
0047 }
0048 
0049 void KWindowInfo::Private::updateData()
0050 {
0051     ProcessInfoRec pinfo;
0052     char processName[512];
0053 #ifdef Q_OS_MAC32
0054     FSSpec appSpec;
0055 #else
0056     FSRef ref;
0057 #endif
0058     pinfo.processInfoLength = sizeof pinfo;
0059     pinfo.processName = (unsigned char *)processName;
0060 #ifdef Q_OS_MAC32
0061     pinfo.processAppSpec = &appSpec;
0062 #else
0063     pinfo.processAppRef = &ref;
0064 #endif
0065     GetProcessInformation(&m_psn, &pinfo);
0066     name = QString::fromLatin1(processName + 1, processName[0]);
0067 
0068     if (m_axWin) {
0069         CFStringRef title;
0070         if (AXUIElementCopyAttributeValue(m_axWin, kAXTitleAttribute, (CFTypeRef *)&title) == noErr) {
0071             CFStringGetCString(title, processName, sizeof processName, kCFStringEncodingUTF8);
0072             name = QString::fromUtf8(processName);
0073         }
0074     }
0075 
0076 #ifdef Q_OS_MAC32
0077     iconSpec = appSpec;
0078 
0079     FSRef ref;
0080     FSpMakeFSRef(&appSpec, &ref);
0081 #else
0082     iconSpec = ref;
0083 #endif
0084     // check if it is in an application bundle (foo.app/Contents/MacOS/plasma)
0085     HFSUniStr255 name;
0086     FSRef parentRef;
0087     FSGetCatalogInfo(&ref, kFSCatInfoNone, 0, &name, 0, &parentRef);
0088     ref = parentRef;
0089     FSGetCatalogInfo(&ref, kFSCatInfoNone, 0, &name, 0, &parentRef);
0090     if (QString::fromUtf16(name.unicode, name.length) == "MacOS") {
0091         ref = parentRef;
0092         FSGetCatalogInfo(&ref, kFSCatInfoNone, 0, &name, 0, &parentRef);
0093         if (QString::fromUtf16(name.unicode, name.length) == "Contents") {
0094 #ifdef Q_OS_MAC32
0095             FSSpec spec;
0096             ref = parentRef;
0097             FSGetCatalogInfo(&ref, kFSCatInfoNone, 0, &name, &spec, &parentRef);
0098             iconSpec = spec;
0099 #else
0100             iconSpec = parentRef;
0101 #endif
0102         }
0103     }
0104 
0105     loadedData = true;
0106 }
0107 
0108 KWindowInfo::KWindowInfo(WId win, unsigned long, unsigned long)
0109     : d(new Private)
0110 {
0111     d->ref = 1;
0112     d->win = win;
0113     d->isLocal = true;
0114     if (!win) {
0115         d->win = (WId)d;
0116         d->isLocal = false;
0117     }
0118 }
0119 
0120 // this one is only to make QList<> or similar happy
0121 KWindowInfo::KWindowInfo()
0122     : d(nullptr)
0123 {
0124 }
0125 
0126 KWindowInfo::~KWindowInfo()
0127 {
0128     if (d != nullptr) {
0129         if (--d->ref == 0) {
0130             delete d;
0131         }
0132     }
0133 }
0134 
0135 KWindowInfo::KWindowInfo(const KWindowInfo &wininfo)
0136     : d(wininfo.d)
0137 {
0138     if (d != nullptr) {
0139         ++d->ref;
0140     }
0141 }
0142 
0143 KWindowInfo &KWindowInfo::operator=(const KWindowInfo &wininfo)
0144 {
0145     if (d != wininfo.d) {
0146         if (d != nullptr)
0147             if (--d->ref == 0) {
0148                 delete d;
0149             }
0150         d = wininfo.d;
0151         if (d != nullptr) {
0152             ++d->ref;
0153         }
0154     }
0155     return *this;
0156 }
0157 
0158 bool KWindowInfo::valid(bool withdrawn_is_valid) const
0159 {
0160     return d->pid() >= 0;
0161 }
0162 
0163 WId KWindowInfo::win() const
0164 {
0165     return d->win;
0166 }
0167 
0168 unsigned long KWindowInfo::state() const
0169 {
0170     return 0;
0171 }
0172 
0173 bool KWindowInfo::hasState(unsigned long s) const
0174 {
0175     return false;
0176 }
0177 
0178 bool KWindowInfo::isMinimized() const
0179 {
0180     if (d->axElement()) {
0181         CFBooleanRef val;
0182         if (AXUIElementCopyAttributeValue(d->axElement(), kAXMinimizedAttribute, (CFTypeRef *)&val) == noErr) {
0183             return CFBooleanGetValue(val);
0184         } else {
0185             return false;
0186         }
0187     } else {
0188         return false;
0189     }
0190 }
0191 
0192 NET::MappingState KWindowInfo::mappingState() const
0193 {
0194     return (NET::MappingState)0;
0195 }
0196 
0197 NETExtendedStrut KWindowInfo::extendedStrut() const
0198 {
0199     NETExtendedStrut ext;
0200     return ext;
0201 }
0202 
0203 NET::WindowType KWindowInfo::windowType(int supported_types) const
0204 {
0205     return (NET::WindowType)0;
0206 }
0207 
0208 QString KWindowInfo::visibleNameWithState() const
0209 {
0210     QString s = visibleName();
0211     if (isMinimized()) {
0212         s.prepend(QLatin1Char('('));
0213         s.append(QLatin1Char(')'));
0214     }
0215     return s;
0216 }
0217 
0218 QString KWindowInfo::visibleName() const
0219 {
0220     return name();
0221 }
0222 
0223 QString KWindowInfo::name() const
0224 {
0225     if (!d->loadedData) {
0226         d->updateData();
0227     }
0228     return d->name;
0229 }
0230 
0231 QString KWindowInfo::visibleIconNameWithState() const
0232 {
0233     QString s = visibleIconName();
0234     if (isMinimized()) {
0235         s.prepend(QLatin1Char('('));
0236         s.append(QLatin1Char(')'));
0237     }
0238     return s;
0239 }
0240 
0241 QString KWindowInfo::visibleIconName() const
0242 {
0243     return visibleName();
0244 }
0245 
0246 QString KWindowInfo::iconName() const
0247 {
0248     return name();
0249 }
0250 
0251 bool KWindowInfo::isOnCurrentDesktop() const
0252 {
0253     return isOnDesktop(KWindowSystem::currentDesktop());
0254 }
0255 
0256 bool KWindowInfo::isOnDesktop(int _desktop) const
0257 {
0258     return true;
0259 }
0260 
0261 bool KWindowInfo::onAllDesktops() const
0262 {
0263     return false;
0264 }
0265 
0266 int KWindowInfo::desktop() const
0267 {
0268     return 0;
0269 }
0270 
0271 QRect KWindowInfo::geometry() const
0272 {
0273     return QRect();
0274 }
0275 
0276 QRect KWindowInfo::frameGeometry() const
0277 {
0278     return QRect();
0279 }
0280 
0281 bool KWindowInfo::actionSupported(NET::Action action) const
0282 {
0283     return true; // no idea if it's supported or not -> pretend it is
0284 }
0285 
0286 #if 0
0287 WId KWindowInfo::transientFor() const
0288 {
0289     kWarning((d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2TransientFor) == 0, 176)
0290             << "Pass NET::WM2TransientFor to KWindowInfo";
0291     return d->info->transientFor();
0292 }
0293 
0294 WId KWindowInfo::groupLeader() const
0295 {
0296     kWarning((d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2GroupLeader) == 0, 176)
0297             << "Pass NET::WM2GroupLeader to KWindowInfo";
0298     return d->info->groupLeader();
0299 }
0300 
0301 QByteArray KWindowInfo::windowClassClass() const
0302 {
0303     kWarning((d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2WindowClass) == 0, 176)
0304             << "Pass NET::WM2WindowClass to KWindowInfo";
0305     return d->info->windowClassClass();
0306 }
0307 
0308 QByteArray KWindowInfo::windowClassName() const
0309 {
0310     kWarning((d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2WindowClass) == 0, 176)
0311             << "Pass NET::WM2WindowClass to KWindowInfo";
0312     return d->info->windowClassName();
0313 }
0314 
0315 QByteArray KWindowInfo::windowRole() const
0316 {
0317     kWarning((d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2WindowRole) == 0, 176)
0318             << "Pass NET::WM2WindowRole to KWindowInfo";
0319     return d->info->windowRole();
0320 }
0321 
0322 QByteArray KWindowInfo::clientMachine() const
0323 {
0324     kWarning((d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2ClientMachine) == 0, 176)
0325             << "Pass NET::WM2ClientMachine to KWindowInfo";
0326     return d->info->clientMachine();
0327 }
0328 
0329 bool KWindowInfo::actionSupported(NET::Action action) const
0330 {
0331     kWarning((d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2AllowedActions) == 0, 176)
0332             << "Pass NET::WM2AllowedActions to KWindowInfo";
0333     if (KWindowSystem::allowedActionsSupported()) {
0334         return d->info->allowedActions() & action;
0335     } else {
0336         return true;    // no idea if it's supported or not -> pretend it is
0337     }
0338 }
0339 
0340 // see NETWM spec section 7.6
0341 bool KWindowInfo::isMinimized() const
0342 {
0343     if (mappingState() != NET::Iconic) {
0344         return false;
0345     }
0346     // NETWM 1.2 compliant WM - uses NET::Hidden for minimized windows
0347     if ((state() & NET::Hidden) != 0
0348             && (state() & NET::Shaded) == 0) {  // shaded may have NET::Hidden too
0349         return true;
0350     }
0351     // older WMs use WithdrawnState for other virtual desktops
0352     // and IconicState only for minimized
0353     return KWindowSystem::icccmCompliantMappingState() ? false : true;
0354 }
0355 #endif