LeechCraft 0.6.70-14794-g33744ae6ce
Modular cross-platform feature rich live environment.
Loading...
Searching...
No Matches
xwrapper.cpp
Go to the documentation of this file.
1/**********************************************************************
2 * LeechCraft - modular cross-platform feature rich internet client.
3 * Copyright (C) 2006-2014 Georg Rudoy
4 *
5 * Distributed under the Boost Software License, Version 1.0.
6 * (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt)
7 **********************************************************************/
8
9#include "xwrapper.h"
10#include <limits>
11#include <type_traits>
12#include <bit>
13#include <QString>
14#include <QPixmap>
15#include <QIcon>
16#include <QApplication>
17#include <QWidget>
18#include <QDesktopWidget>
19#include <QAbstractEventDispatcher>
20#include <QtDebug>
21#include <QScreen>
22#include <X11/Xlib.h>
23#include <X11/Xutil.h>
24#include <X11/Xatom.h>
25#include <xcb/xcb.h>
26#include <util/sll/qtutil.h>
27
28namespace LC::Util
29{
30 const int SourcePager = 2;
31
32 const int StateRemove = 0;
33 const int StateAdd = 1;
34
35 XWrapper::XWrapper ()
36 : Display_ (QX11Info::display ())
37 , AppWin_ (QX11Info::appRootWindow ())
38 {
39 QAbstractEventDispatcher::instance ()->installNativeEventFilter (this);
40
41 const uint32_t rootEvents [] =
42 {
43 XCB_EVENT_MASK_STRUCTURE_NOTIFY |
44 XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
45 XCB_EVENT_MASK_PROPERTY_CHANGE
46 };
47 xcb_change_window_attributes (QX11Info::connection (),
48 AppWin_, XCB_CW_EVENT_MASK, rootEvents);
49 }
50
51 XWrapper& XWrapper::Instance ()
52 {
53 static XWrapper w;
54 return w;
55 }
56
57 Display* XWrapper::GetDisplay () const
58 {
59 return Display_;
60 }
61
62 Window XWrapper::GetRootWindow () const
63 {
64 return AppWin_;
65 }
66
67 bool XWrapper::nativeEventFilter (const QByteArray& eventType, void *msg, long int*)
68 {
69 if (eventType != "xcb_generic_event_t")
70 return false;
71
72 const auto ev = static_cast<xcb_generic_event_t*> (msg);
73 if ((ev->response_type & ~0x80) == XCB_PROPERTY_NOTIFY)
74 HandlePropNotify (static_cast<xcb_property_notify_event_t*> (msg));
75
76 return false;
77 }
78
79 namespace
80 {
81 template<typename T>
82 struct IsDoublePtr : std::false_type {};
83
84 template<typename T>
85 struct IsDoublePtr<T**> : std::true_type {};
86
87 template<typename T>
88 class Guarded
89 {
90 T *Data_ = nullptr;
91 public:
92 Guarded () = default;
93
94 Guarded (const Guarded&) = delete;
95 Guarded& operator= (const Guarded&) = delete;
96
97 Guarded (Guarded&& other) noexcept
98 : Data_ { other.Data_ }
99 {
100 other.Data_ = nullptr;
101 }
102
103 Guarded& operator= (Guarded&& other) noexcept
104 {
105 std::swap (Data_, other.Data_);
106 return *this;
107 }
108
109 ~Guarded () noexcept
110 {
111 if (Data_)
112 XFree (Data_);
113 }
114
115 T** Get (bool clear = true) noexcept
116 {
117 if (clear && Data_)
118 XFree (Data_);
119 return &Data_;
120 }
121
122 template<typename U>
123 U GetAs (bool clear = true) noexcept
124 {
125 if (clear && Data_)
126 XFree (Data_);
127 return IsDoublePtr<U>::value ?
128 reinterpret_cast<U> (&Data_) :
129 reinterpret_cast<U> (Data_);
130 }
131
132 T operator[] (size_t idx) const noexcept
133 {
134 return Data_ [idx];
135 }
136
137 T& operator[] (size_t idx) noexcept
138 {
139 return Data_ [idx];
140 }
141
142 explicit operator bool () const noexcept
143 {
144 return Data_ != nullptr;
145 }
146
147 bool operator! () const noexcept
148 {
149 return !Data_;
150 }
151 };
152 }
153
154 void XWrapper::Sync ()
155 {
156 XFlush (Display_);
157 XSync (Display_, False);
158 }
159
160 QList<Window> XWrapper::GetWindows ()
161 {
162 ulong length = 0;
163 Guarded<Window> data;
164
165 QList<Window> result;
166 if (GetRootWinProp (GetAtom ("_NET_CLIENT_LIST"), &length, data.GetAs<uchar**> ()))
167 for (ulong i = 0; i < length; ++i)
168 result << data [i];
169 return result;
170 }
171
172 QString XWrapper::GetWindowTitle (Window wid)
173 {
174 QString name;
175
176 ulong length = 0;
177 Guarded<uchar> data;
178
179 auto utf8Str = GetAtom ("UTF8_STRING");
180
181 if (GetWinProp (wid, GetAtom ("_NET_WM_VISIBLE_NAME"), &length, data.Get (), utf8Str))
182 name = QString::fromUtf8 (data.GetAs<char*> (false));
183
184 if (name.isEmpty () && GetWinProp (wid, GetAtom ("_NET_WM_NAME"), &length, data.Get (), utf8Str))
185 name = QString::fromUtf8 (data.GetAs<char*> (false));
186
187 if (name.isEmpty () && GetWinProp (wid, GetAtom ("XA_WM_NAME"), &length, data.Get (), XA_STRING))
188 name = QString::fromUtf8 (data.GetAs<char*> (false));
189
190 if (name.isEmpty ())
191 {
192 XFetchName (Display_, wid, data.GetAs<char**> ());
193 name = QString (data.GetAs<char*> (false));
194 }
195
196 if (name.isEmpty ())
197 {
198 XTextProperty prop;
199 if (XGetWMName (Display_, wid, &prop))
200 {
201 name = QString::fromUtf8 (reinterpret_cast<char*> (prop.value));
202 XFree (prop.value);
203 }
204 }
205
206 return name;
207 }
208
209 QIcon XWrapper::GetWindowIcon (Window wid)
210 {
211 int fmt = 0;
212 ulong type, count, extra;
213 Guarded<ulong> data;
214
215 XGetWindowProperty (Display_, wid, GetAtom ("_NET_WM_ICON"),
216 0, std::numeric_limits<long>::max (), False, AnyPropertyType,
217 &type, &fmt, &count, &extra,
218 data.GetAs<uchar**> ());
219
220 if (!data)
221 return {};
222
223 QIcon icon;
224
225 auto cur = *data.Get (false);
226 auto end = cur + count;
227 while (cur < end)
228 {
229 QImage img (cur [0], cur [1], QImage::Format_ARGB32);
230 cur += 2;
231 const auto bytesCount = img.sizeInBytes ();
232 for (int i = 0; i < bytesCount / 4; ++i, ++cur)
233 reinterpret_cast<uint*> (img.bits ()) [i] = *cur;
234
235 icon.addPixmap (QPixmap::fromImage (img));
236 }
237
238 return icon;
239 }
240
241 template<typename Flag>
242 QFlags<Flag> XWrapper::GetFlagsList (Window wid, Atom property, const QHash<Atom, Flag>& atom2flag) const
243 {
244 QFlags<Flag> result;
245
246 ulong length = 0;
247 ulong *data = 0;
248 if (!GetWinProp (wid, property, &length, reinterpret_cast<uchar**> (&data), XA_ATOM))
249 return result;
250
251 for (ulong i = 0; i < length; ++i)
252 result |= atom2flag.value (data [i], static_cast<Flag> (0));
253
254 XFree (data);
255
256 return result;
257 }
258
259 WinStateFlags XWrapper::GetWindowState (Window wid)
260 {
261 auto get = [this] (const QByteArray& atom) { return GetAtom (AsStringView ("_NET_WM_STATE_" + atom)); };
262 static const QHash<Atom, WinStateFlag> atom2flag
263 {
264 { get ("MODAL"), WinStateFlag::Modal },
265 { get ("STICKY"), WinStateFlag::Sticky },
266 { get ("MAXIMIZED_VERT"), WinStateFlag::MaximizedVert },
267 { get ("MAXIMIZED_HORZ"), WinStateFlag::MaximizedHorz },
268 { get ("SHADED"), WinStateFlag::Shaded },
269 { get ("SKIP_TASKBAR"), WinStateFlag::SkipTaskbar },
270 { get ("SKIP_PAGER"), WinStateFlag::SkipPager },
271 { get ("HIDDEN"), WinStateFlag::Hidden },
272 { get ("FULLSCREEN"), WinStateFlag::Fullscreen },
273 { get ("ABOVE"), WinStateFlag::OnTop },
274 { get ("BELOW"), WinStateFlag::OnBottom },
275 { get ("DEMANDS_ATTENTION"), WinStateFlag::Attention },
276 };
277
278 return GetFlagsList (wid, GetAtom ("_NET_WM_STATE"), atom2flag);
279 }
280
281 AllowedActionFlags XWrapper::GetWindowActions (Window wid)
282 {
283 auto get = [this] (const QByteArray& atom) { return GetAtom (AsStringView ("_NET_WM_ACTION_" + atom)); };
284 static const QHash<Atom, AllowedActionFlag> atom2flag
285 {
286 { get ("MOVE"), AllowedActionFlag::Move },
287 { get ("RESIZE"), AllowedActionFlag::Resize },
288 { get ("MINIMIZE"), AllowedActionFlag::Minimize },
289 { get ("SHADE"), AllowedActionFlag::Shade },
290 { get ("STICK"), AllowedActionFlag::Stick },
291 { get ("MAXIMIZE_HORZ"), AllowedActionFlag::MaximizeHorz },
292 { get ("MAXIMIZE_VERT"), AllowedActionFlag::MaximizeVert },
293 { get ("FULLSCREEN"), AllowedActionFlag::ShowFullscreen },
294 { get ("CHANGE_DESKTOP"), AllowedActionFlag::ChangeDesktop },
295 { get ("CLOSE"), AllowedActionFlag::Close },
296 { get ("ABOVE"), AllowedActionFlag::MoveToTop },
297 { get ("BELOW"), AllowedActionFlag::MoveToBottom },
298 };
299
300 return GetFlagsList (wid, GetAtom ("_NET_WM_ALLOWED_ACTIONS"), atom2flag);
301 }
302
303 Window XWrapper::GetActiveApp ()
304 {
305 auto win = GetActiveWindow ();
306 if (!win)
307 return 0;
308
309 Window transient = None;
310 if (!ShouldShow (win) && XGetTransientForHint (Display_, win, &transient))
311 return transient;
312
313 return win;
314 }
315
316 bool XWrapper::IsLCWindow (Window wid)
317 {
318 ulong length = 0;
319 Guarded<uchar> data;
320 return GetWinProp (wid, GetAtom ("WM_CLASS"), &length, data.Get ()) &&
321 QString (data.GetAs<char*> (false)).startsWith ("leechcraft"_ql);
322 }
323
324 bool XWrapper::ShouldShow (Window wid)
325 {
326 static const QList<Atom> ignoreAtoms
327 {
328 GetAtom ("_NET_WM_WINDOW_TYPE_DESKTOP"),
329 GetAtom ("_NET_WM_WINDOW_TYPE_DOCK"),
330 GetAtom ("_NET_WM_WINDOW_TYPE_TOOLBAR"),
331 GetAtom ("_NET_WM_WINDOW_TYPE_UTILITY"),
332 GetAtom ("_NET_WM_WINDOW_TYPE_MENU"),
333 GetAtom ("_NET_WM_WINDOW_TYPE_SPLASH"),
334 GetAtom ("_NET_WM_WINDOW_TYPE_POPUP_MENU")
335 };
336
337 for (const auto& type : GetWindowType (wid))
338 if (ignoreAtoms.contains (type))
339 return false;
340
341 if (GetWindowState (wid) & WinStateFlag::SkipTaskbar)
342 return false;
343
344 Window transient = None;
345 if (!XGetTransientForHint (Display_, wid, &transient))
346 return true;
347
348 if (transient == 0 || transient == wid || transient == AppWin_)
349 return true;
350
351 return !GetWindowType (transient).contains (GetAtom ("_NET_WM_WINDOW_TYPE_NORMAL"));
352 }
353
354 void XWrapper::Subscribe (Window wid)
355 {
356 if (IsLCWindow (wid))
357 return;
358
359 XSelectInput (Display_, wid, PropertyChangeMask);
360 }
361
362 void XWrapper::SetStrut (QWidget *widget, Qt::ToolBarArea area)
363 {
364 const auto wid = widget->effectiveWinId ();
365
366 const auto& winGeom = widget->geometry ();
367
368 switch (area)
369 {
370 case Qt::BottomToolBarArea:
371 SetStrut (wid,
372 0, 0, 0, winGeom.height (),
373 0, 0,
374 0, 0,
375 0, 0,
376 winGeom.left (), winGeom.right ());
377 break;
378 case Qt::TopToolBarArea:
379 SetStrut (wid,
380 0, 0, winGeom.height (), 0,
381 0, 0,
382 0, 0,
383 winGeom.left (), winGeom.right (),
384 0, 0);
385 break;
386 case Qt::LeftToolBarArea:
387 SetStrut (wid,
388 winGeom.width (), 0, 0, 0,
389 winGeom.top (), winGeom.bottom (),
390 0, 0,
391 0, 0,
392 0, 0);
393 break;
394 case Qt::RightToolBarArea:
395 SetStrut (wid,
396 0, winGeom.width (), 0, 0,
397 0, 0,
398 winGeom.top (), winGeom.bottom (),
399 0, 0,
400 0, 0);
401 break;
402 default:
403 qWarning () << Q_FUNC_INFO
404 << "incorrect area passed"
405 << area;
406 break;
407 }
408 }
409
410 void XWrapper::ClearStrut (QWidget *w)
411 {
412 const auto wid = w->effectiveWinId ();
413 XDeleteProperty (Display_, wid, GetAtom ("_NET_WM_STRUT"));
414 XDeleteProperty (Display_, wid, GetAtom ("_NET_WM_STRUT_PARTIAL"));
415 }
416
417 void XWrapper::SetStrut (Window wid,
418 ulong left, ulong right, ulong top, ulong bottom,
419 ulong leftStartY, ulong leftEndY,
420 ulong rightStartY, ulong rightEndY,
421 ulong topStartX, ulong topEndX,
422 ulong bottomStartX, ulong bottomEndX)
423 {
424 ulong struts [12] =
425 {
426 left,
427 right,
428 top,
429 bottom,
430
431 leftStartY,
432 leftEndY,
433 rightStartY,
434 rightEndY,
435
436 topStartX,
437 topEndX,
438 bottomStartX,
439 bottomEndX
440 };
441
442 XChangeProperty (Display_, wid, GetAtom ("_NET_WM_STRUT_PARTIAL"),
443 XA_CARDINAL, 32, PropModeReplace, reinterpret_cast<uchar*> (struts), 12);
444
445 XChangeProperty (Display_, wid, GetAtom ("_NET_WM_STRUT"),
446 XA_CARDINAL, 32, PropModeReplace, reinterpret_cast<uchar*> (struts), 4);
447 }
448
449 void XWrapper::RaiseWindow (Window wid)
450 {
451 SendMessage (wid, GetAtom ("_NET_ACTIVE_WINDOW"), SourcePager);
452 }
453
454 void XWrapper::MinimizeWindow (Window wid)
455 {
456 SendMessage (wid, GetAtom ("WM_CHANGE_STATE"), IconicState);
457 }
458
459 void XWrapper::MaximizeWindow (Window wid)
460 {
461 SendMessage (wid, GetAtom ("_NET_WM_STATE"), StateAdd,
462 GetAtom ("_NET_WM_STATE_MAXIMIZED_VERT"),
463 GetAtom ("_NET_WM_STATE_MAXIMIZED_HORZ"),
465 }
466
467 void XWrapper::UnmaximizeWindow (Window wid)
468 {
469 SendMessage (wid, GetAtom ("_NET_WM_STATE"), StateRemove,
470 GetAtom ("_NET_WM_STATE_MAXIMIZED_VERT"),
471 GetAtom ("_NET_WM_STATE_MAXIMIZED_HORZ"),
473 }
474
475 void XWrapper::ResizeWindow (Window wid, int width, int height)
476 {
477 XResizeWindow (Display_, wid, width, height);
478 }
479
480 void XWrapper::ShadeWindow (Window wid)
481 {
482 SendMessage (wid, GetAtom ("_NET_WM_STATE"),
483 StateAdd, GetAtom ("_NET_WM_STATE_SHADED"), 0, SourcePager);
484 }
485
486 void XWrapper::UnshadeWindow (Window wid)
487 {
488 SendMessage (wid, GetAtom ("_NET_WM_STATE"),
489 StateRemove, GetAtom ("_NET_WM_STATE_SHADED"), 0, SourcePager);
490 }
491
492 void XWrapper::MoveWindowTo (Window wid, Layer layer)
493 {
494 const auto top = layer == Layer::Top ? StateAdd : StateRemove;
495 const auto bottom = layer == Layer::Bottom ? StateAdd : StateRemove;
496
497 SendMessage (wid, GetAtom ("_NET_WM_STATE"), top,
498 GetAtom ("_NET_WM_STATE_ABOVE"), 0, SourcePager);
499
500 SendMessage (wid, GetAtom ("_NET_WM_STATE"), bottom,
501 GetAtom ("_NET_WM_STATE_BELOW"), 0, SourcePager);
502 }
503
504 void XWrapper::CloseWindow (Window wid)
505 {
506 SendMessage (wid, GetAtom ("_NET_CLOSE_WINDOW"), 0, SourcePager);
507 }
508
509 template<typename T>
510 void XWrapper::HandlePropNotify (T ev)
511 {
512 if (ev->state == XCB_PROPERTY_DELETE)
513 return;
514
515 const auto wid = ev->window;
516
517 if (wid == AppWin_)
518 {
519 if (ev->atom == GetAtom ("_NET_CLIENT_LIST"))
520 emit windowListChanged ();
521 else if (ev->atom == GetAtom ("_NET_ACTIVE_WINDOW"))
522 emit activeWindowChanged ();
523 else if (ev->atom == GetAtom ("_NET_CURRENT_DESKTOP"))
524 emit desktopChanged ();
525 }
526 else
527 {
528 if (ev->atom == GetAtom ("_NET_WM_VISIBLE_NAME") ||
529 ev->atom == GetAtom ("WM_NAME"))
530 emit windowNameChanged (wid);
531 else if (ev->atom == GetAtom ("_NET_WM_ICON"))
532 emit windowIconChanged (wid);
533 else if (ev->atom == GetAtom ("_NET_WM_DESKTOP"))
534 emit windowDesktopChanged (wid);
535 else if (ev->atom == GetAtom ("_NET_WM_STATE"))
536 emit windowStateChanged (wid);
537 else if (ev->atom == GetAtom ("_NET_WM_ALLOWED_ACTIONS"))
538 emit windowActionsChanged (wid);
539 }
540 }
541
542 Window XWrapper::GetActiveWindow ()
543 {
544 ulong length = 0;
545 Guarded<ulong> data;
546
547 if (!GetRootWinProp (GetAtom ("_NET_ACTIVE_WINDOW"), &length, data.GetAs<uchar**> (), XA_WINDOW))
548 return 0;
549
550 if (!length)
551 return 0;
552
553 return data [0];
554 }
555
556 int XWrapper::GetDesktopCount ()
557 {
558 ulong length = 0;
559 Guarded<ulong> data;
560
561 if (GetRootWinProp (GetAtom ("_NET_NUMBER_OF_DESKTOPS"), &length, data.GetAs<uchar**> (), XA_CARDINAL))
562 return length > 0 ? data [0] : -1;
563
564 return -1;
565 }
566
567 int XWrapper::GetCurrentDesktop ()
568 {
569 ulong length = 0;
570 Guarded<ulong> data;
571
572 if (GetRootWinProp (GetAtom ("_NET_CURRENT_DESKTOP"), &length, data.GetAs<uchar**> (), XA_CARDINAL))
573 return length > 0 ? data [0] : -1;
574
575 return -1;
576 }
577
578 void XWrapper::SetCurrentDesktop (int desktop)
579 {
580 SendMessage (AppWin_, GetAtom ("_NET_CURRENT_DESKTOP"), desktop);
581 }
582
583 QStringList XWrapper::GetDesktopNames ()
584 {
585 ulong length = 0;
586 Guarded<uchar> data;
587
588 if (!GetRootWinProp (GetAtom ("_NET_DESKTOP_NAMES"),
589 &length, data.GetAs<uchar**> (), GetAtom ("UTF8_STRING")))
590 return {};
591
592 if (!data)
593 return {};
594
595 QStringList result;
596 for (char *pos = data.GetAs<char*> (false), *end = data.GetAs<char*> (false) + length; pos < end; )
597 {
598 const auto& str = QString::fromUtf8 (pos);
599 result << str;
600 pos += str.toUtf8 ().size () + 1;
601 }
602 return result;
603 }
604
605 QString XWrapper::GetDesktopName (int desktop, const QString& def)
606 {
607 return GetDesktopNames ().value (desktop, def);
608 }
609
610 int XWrapper::GetWindowDesktop (Window wid)
611 {
612 ulong length = 0;
613 Guarded<ulong> data;
614 if (GetWinProp (wid, GetAtom ("_NET_WM_DESKTOP"), &length, data.GetAs<uchar**> (), XA_CARDINAL) && length)
615 return data [0];
616
617 if (GetWinProp (wid, GetAtom ("_WIN_WORKSPACE"), &length, data.GetAs<uchar**> (), XA_CARDINAL) && length)
618 return data [0];
619
620 return -1;
621 }
622
623 void XWrapper::MoveWindowToDesktop (Window wid, int num)
624 {
625 unsigned long data = num;
626 XChangeProperty (QX11Info::display (),
627 wid,
628 GetAtom ("_NET_WM_DESKTOP"),
629 XA_CARDINAL,
630 32,
631 PropModeReplace,
632 reinterpret_cast<unsigned char*> (&data),
633 1);
634 }
635
636 QRect XWrapper::GetAvailableGeometry (int screenIdx)
637 {
638 auto dw = QApplication::desktop ();
639
640 const auto& screens = QGuiApplication::screens ();
641 auto screen = screens.value (screenIdx, QGuiApplication::primaryScreen ());
642
643 auto available = screen->geometry ();
644 const auto deskGeom = dw->rect ();
645
646 for (const auto wid : GetWindows ())
647 {
648 ulong length = 0;
649 Guarded<ulong> struts;
650 const auto status = GetWinProp (wid, GetAtom ("_NET_WM_STRUT_PARTIAL"),
651 &length, struts.GetAs<uchar**> (), XA_CARDINAL);
652 if (!status || length != 12)
653 continue;
654
655 const QRect left
656 {
657 static_cast<int> (deskGeom.x ()),
658 static_cast<int> (deskGeom.y () + struts [4]),
659 static_cast<int> (struts [0]),
660 static_cast<int> (struts [5] - struts [4])
661 };
662 if (available.intersects (left))
663 available.setX (left.width ());
664
665 const QRect right
666 {
667 static_cast<int> (deskGeom.x () + deskGeom.width () - struts [1]),
668 static_cast<int> (deskGeom.y () + struts [6]),
669 static_cast<int> (struts [1]),
670 static_cast<int> (struts [7] - struts [6])
671 };
672 if (available.intersects (right))
673 available.setWidth (right.x () - available.x ());
674
675 const QRect top
676 {
677 static_cast<int> (deskGeom.x () + struts [8]),
678 static_cast<int> (deskGeom.y ()),
679 static_cast<int> (struts [9] - struts [8]),
680 static_cast<int> (struts [2])
681 };
682 if (available.intersects (top))
683 available.setY (top.height ());
684
685 const QRect bottom
686 {
687 static_cast<int> (deskGeom.x () + struts [10]),
688 static_cast<int> (deskGeom.y () + deskGeom.height () - struts [3]),
689 static_cast<int> (struts [11] - struts [10]),
690 static_cast<int> (struts [3])
691 };
692 if (available.intersects (bottom))
693 available.setHeight (bottom.y () - available.y ());
694 }
695
696 return available;
697 }
698
699 QRect XWrapper::GetAvailableGeometry (QWidget *widget)
700 {
701 return GetAvailableGeometry (QApplication::desktop ()->screenNumber (widget));
702 }
703
704 Atom XWrapper::GetAtom (std::string_view name)
705 {
706 const auto pos = Atoms_.find (AsByteArray (name));
707 if (pos != Atoms_.end ())
708 return *pos;
709
710 auto atom = XInternAtom (Display_, name.data (), false);
711 Atoms_ [ToByteArray (name)] = atom;
712 return atom;
713 }
714
715 bool XWrapper::GetWinProp (Window win, Atom property,
716 ulong *length, unsigned char **result, Atom req) const
717 {
718 int fmt = 0;
719 ulong type = 0, rest = 0;
720 return XGetWindowProperty (Display_, win,
721 property, 0, 1024, false, req, &type,
722 &fmt, length, &rest, result) == Success;
723 }
724
725 bool XWrapper::GetRootWinProp (Atom property,
726 ulong *length, uchar **result, Atom req) const
727 {
728 return GetWinProp (AppWin_, property, length, result, req);
729 }
730
731 QList<Atom> XWrapper::GetWindowType (Window wid)
732 {
733 QList<Atom> result;
734
735 ulong length = 0;
736 ulong *data = nullptr;
737
738 if (!GetWinProp (wid, GetAtom ("_NET_WM_WINDOW_TYPE"),
739 &length, reinterpret_cast<uchar**> (&data)))
740 return result;
741
742 for (ulong i = 0; i < length; ++i)
743 result << data [i];
744
745 XFree (data);
746 return result;
747 }
748
749 bool XWrapper::SendMessage (Window wid, Atom atom, ulong d0, ulong d1, ulong d2, ulong d3, ulong d4)
750 {
751 XEvent msg;
752 msg.xclient.window = wid;
753 msg.xclient.type = ClientMessage;
754 msg.xclient.message_type = atom;
755 msg.xclient.send_event = true;
756 msg.xclient.display = Display_;
757 msg.xclient.format = 32;
758 msg.xclient.data.l [0] = d0;
759 msg.xclient.data.l [1] = d1;
760 msg.xclient.data.l [2] = d2;
761 msg.xclient.data.l [3] = d3;
762 msg.xclient.data.l [4] = d4;
763
764 auto flags = SubstructureRedirectMask | SubstructureNotifyMask;
765 return XSendEvent (Display_, AppWin_, false, flags, &msg) == Success;
766 }
767
768 void XWrapper::initialize ()
769 {
770 }
771}
QByteArray AsByteArray(std::string_view view)
Convert the view into a QByteArray without copying.
Definition: qtutil.h:68
const int StateRemove
Definition: xwrapper.cpp:32
const int SourcePager
Definition: xwrapper.cpp:30
const int StateAdd
Definition: xwrapper.cpp:33
QByteArray ToByteArray(std::string_view view)
Create a QByteArray with the data referenced by the view.
Definition: qtutil.h:83
std::string_view AsStringView(const QByteArray &arr)
Create a std::string_view referring the data within a QByteArray.
Definition: qtutil.h:93
union _XEvent XEvent
Definition: xwrapper.h:29
unsigned long Window
Definition: xwrapper.h:26