1 /*
2     This file is part of the KDE libraries
3     SPDX-FileCopyrightText: 2008 Carlo Segato <brandon.ml@gmail.com>
4     SPDX-FileCopyrightText: 2011 Pau Garcia i Quiles <pgquiles@elpauer.org>
5 
6     SPDX-License-Identifier: LGPL-2.1-or-later
7 */
8 
9 #include "kwindowinfo.h"
10 #include "kwindowsystem.h"
11 #include <QCoreApplication>
12 #include <stdlib.h>
13 #include <windows.h>
14 
15 class Q_DECL_HIDDEN KWindowInfo::Private
16 {
17 public:
Private()18     Private()
19         : properties(0)
20         , properties2(0)
21     {
22     }
23 
~Private()24     ~Private()
25     {
26     }
27 
28     HWND win_;
29     int ref;
30     unsigned long properties;
31     unsigned long properties2;
32 
33 private:
34     Private(const Private &);
35     void operator=(const Private &);
36 };
37 
38 #include <QRect>
39 
KWindowInfo(WId win,unsigned long properties,unsigned long properties2)40 KWindowInfo::KWindowInfo(WId win, unsigned long properties, unsigned long properties2)
41     : d(new Private)
42 {
43     d->ref = 1;
44     d->win_ = reinterpret_cast<HWND>(win);
45     d->properties = properties;
46     d->properties2 = properties2;
47 }
48 
KWindowInfo()49 KWindowInfo::KWindowInfo()
50     : d(nullptr)
51 {
52 }
53 
~KWindowInfo()54 KWindowInfo::~KWindowInfo()
55 {
56     if (d != nullptr) {
57         if (--d->ref == 0) {
58             delete d;
59         }
60     }
61 }
62 
KWindowInfo(const KWindowInfo & wininfo)63 KWindowInfo::KWindowInfo(const KWindowInfo &wininfo)
64     : d(wininfo.d)
65 {
66     if (d != nullptr) {
67         ++d->ref;
68     }
69 }
70 
operator =(const KWindowInfo & wininfo)71 KWindowInfo &KWindowInfo::operator=(const KWindowInfo &wininfo)
72 {
73     if (d != wininfo.d) {
74         if (d != nullptr)
75             if (--d->ref == 0) {
76                 delete d;
77             }
78         d = wininfo.d;
79         if (d != nullptr) {
80             ++d->ref;
81         }
82     }
83     return *this;
84 }
85 
valid(bool withdrawn_is_valid) const86 bool KWindowInfo::valid(bool withdrawn_is_valid) const
87 {
88     return true;
89 }
90 
win() const91 WId KWindowInfo::win() const
92 {
93     return reinterpret_cast<WId>(d->win_);
94 }
95 
state() const96 unsigned long KWindowInfo::state() const
97 {
98     unsigned long state = 0;
99 #ifndef _WIN32_WCE
100     if (IsZoomed(d->win_)) {
101         state |= NET::Max;
102     }
103 #endif
104     if (!IsWindowVisible(d->win_)) {
105         state |= NET::Hidden;
106     }
107 
108 #ifndef _WIN32_WCE
109     LONG_PTR lp = GetWindowLongPtr(d->win_, GWL_EXSTYLE);
110     if (lp & WS_EX_TOOLWINDOW) {
111         state |= NET::SkipTaskbar;
112     }
113 #endif
114 
115     return state;
116 }
117 
hasState(unsigned long s) const118 bool KWindowInfo::hasState(unsigned long s) const
119 {
120     return (state() & s);
121 }
122 
isMinimized() const123 bool KWindowInfo::isMinimized() const
124 {
125 #ifndef _WIN32_WCE
126     return IsIconic(d->win_);
127 #else
128     return false;
129 #endif
130 }
131 
mappingState() const132 NET::MappingState KWindowInfo::mappingState() const
133 {
134 #ifndef _WIN32_WCE
135     if (IsIconic(d->win_)) {
136         return NET::Iconic;
137     }
138 #endif
139     if (!IsWindowVisible(d->win_)) {
140         return NET::Withdrawn;
141     }
142     return NET::Visible;
143 }
144 
extendedStrut() const145 NETExtendedStrut KWindowInfo::extendedStrut() const
146 {
147     return NETExtendedStrut();
148 }
149 
windowType(int supported_types) const150 NET::WindowType KWindowInfo::windowType(int supported_types) const
151 {
152     NET::WindowType wt(NET::Normal);
153 
154     long windowStyle = GetWindowLong(d->win_, GWL_STYLE);
155     long windowStyleEx = GetWindowLong(d->win_, GWL_EXSTYLE);
156 
157     if (windowStyle & WS_POPUP && supported_types & NET::PopupMenuMask) {
158         return NET::PopupMenu;
159     } else if (windowStyleEx & WS_EX_TOOLWINDOW && supported_types & NET::TooltipMask) {
160         return NET::Tooltip;
161     } else if (!(windowStyle & WS_CHILD) && supported_types & NET::NormalMask) {
162         return NET::Normal;
163     }
164 
165     return wt;
166 }
167 
visibleNameWithState() const168 QString KWindowInfo::visibleNameWithState() const
169 {
170     QString s = visibleName();
171     if (isMinimized()) {
172         s.prepend(QLatin1Char('('));
173         s.append(QLatin1Char(')'));
174     }
175     return s;
176 }
177 
visibleName() const178 QString KWindowInfo::visibleName() const
179 {
180     return name();
181 }
182 
name() const183 QString KWindowInfo::name() const
184 {
185     QByteArray windowText = QByteArray((GetWindowTextLength(d->win_) + 1) * sizeof(wchar_t), 0);
186     GetWindowTextW(d->win_, (LPWSTR)windowText.data(), windowText.size());
187     return QString::fromWCharArray((wchar_t *)windowText.data());
188 }
189 
visibleIconNameWithState() const190 QString KWindowInfo::visibleIconNameWithState() const
191 {
192     return QString();
193 }
194 
visibleIconName() const195 QString KWindowInfo::visibleIconName() const
196 {
197     return QString();
198 }
199 
iconName() const200 QString KWindowInfo::iconName() const
201 {
202     return QString();
203 }
204 
isOnCurrentDesktop() const205 bool KWindowInfo::isOnCurrentDesktop() const
206 {
207     return true;
208 }
209 
isOnDesktop(int desk) const210 bool KWindowInfo::isOnDesktop(int desk) const
211 {
212     return desk == desktop();
213 }
214 
onAllDesktops() const215 bool KWindowInfo::onAllDesktops() const
216 {
217     return false;
218 }
219 
desktop() const220 int KWindowInfo::desktop() const
221 {
222     return 1;
223 }
224 
geometry() const225 QRect KWindowInfo::geometry() const
226 {
227     RECT wndRect;
228     memset(&wndRect, 0, sizeof(wndRect));
229 
230     // fetch the geometry INCLUDING the frames
231     if (GetWindowRect(d->win_, &wndRect)) {
232         QRect result;
233         result.setCoords(wndRect.left, wndRect.top, wndRect.right, wndRect.bottom);
234         return result;
235     }
236 
237     return QRect();
238 }
239 
frameGeometry() const240 QRect KWindowInfo::frameGeometry() const
241 {
242     RECT wndRect;
243     memset(&wndRect, 0, sizeof(wndRect));
244 
245     // fetch only client area geometries ... i hope that's right
246     if (GetClientRect(d->win_, &wndRect)) {
247         QRect result;
248         result.setCoords(wndRect.left, wndRect.top, wndRect.right, wndRect.bottom);
249         return result;
250     }
251 
252     return QRect();
253 }
254 
actionSupported(NET::Action action) const255 bool KWindowInfo::actionSupported(NET::Action action) const
256 {
257     return true; // no idea if it's supported or not -> pretend it is
258 }
259 
260 #if 0
261 WId KWindowInfo::transientFor() const
262 {
263     kWarning((d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2TransientFor) == 0, 176)
264             << "Pass NET::WM2TransientFor to KWindowInfo";
265     return d->info->transientFor();
266 }
267 
268 WId KWindowInfo::groupLeader() const
269 {
270     kWarning((d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2GroupLeader) == 0, 176)
271             << "Pass NET::WM2GroupLeader to KWindowInfo";
272     return d->info->groupLeader();
273 }
274 #endif
275 
windowClassClass() const276 QByteArray KWindowInfo::windowClassClass() const
277 {
278     //    kWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2WindowClass ) == 0, 176 )
279     //        << "Pass NET::WM2WindowClass to KWindowInfo";
280     //    return d->info->windowClassClass();
281 
282     // Implemented per http://tronche.com/gui/x/icccm/sec-4.html#WM_CLASS (but only 2nd and 3rd choices, -name ignored)
283     char *resourcenamevar;
284     resourcenamevar = getenv("RESOURCE_NAME");
285     if (resourcenamevar != nullptr) {
286         return QByteArray(resourcenamevar);
287     }
288 
289     return QCoreApplication::applicationName().toLocal8Bit();
290 }
291 
windowClassName() const292 QByteArray KWindowInfo::windowClassName() const
293 {
294     //    kWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2WindowClass ) == 0, 176 )
295     //        << "Pass NET::WM2WindowClass to KWindowInfo";
296     //    return d->info->windowClassName();
297 
298     // Maybe should use RealGetWindowClass instead of GetClassName? See
299     // http://blogs.msdn.com/b/oldnewthing/archive/2010/12/31/10110524.aspx
300 
301     const int max = 256; // truncate to 255 characters
302     TCHAR name[max];
303     int count = GetClassName(d->win_, name, max);
304     return QString::fromUtf16((ushort *)name).toLocal8Bit();
305 }
306 
307 #if 0
308 QByteArray KWindowInfo::windowRole() const
309 {
310     kWarning((d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2WindowRole) == 0, 176)
311             << "Pass NET::WM2WindowRole to KWindowInfo";
312     return d->info->windowRole();
313 }
314 
315 QByteArray KWindowInfo::clientMachine() const
316 {
317     kWarning((d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2ClientMachine) == 0, 176)
318             << "Pass NET::WM2ClientMachine to KWindowInfo";
319     return d->info->clientMachine();
320 }
321 
322 bool KWindowInfo::actionSupported(NET::Action action) const
323 {
324     kWarning((d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2AllowedActions) == 0, 176)
325             << "Pass NET::WM2AllowedActions to KWindowInfo";
326     if (KWindowSystem::allowedActionsSupported()) {
327         return d->info->allowedActions() & action;
328     } else {
329         return true;    // no idea if it's supported or not -> pretend it is
330     }
331 }
332 #endif
333