32 #include <type_traits> 36 #include <QApplication> 38 #include <QDesktopWidget> 39 #include <QAbstractEventDispatcher> 43 #include <X11/Xutil.h> 44 #include <X11/Xatom.h> 57 : Display_ (QX11Info::display ())
58 , AppWin_ (QX11Info::appRootWindow ())
60 QAbstractEventDispatcher::instance ()->installNativeEventFilter (
this);
62 const uint32_t rootEvents [] =
64 XCB_EVENT_MASK_STRUCTURE_NOTIFY |
65 XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
66 XCB_EVENT_MASK_PROPERTY_CHANGE
68 xcb_change_window_attributes (QX11Info::connection (),
69 AppWin_, XCB_CW_EVENT_MASK, rootEvents);
78 Display* XWrapper::GetDisplay ()
const 83 Window XWrapper::GetRootWindow ()
const 88 bool XWrapper::nativeEventFilter (
const QByteArray& eventType,
void *msg,
long int*)
90 if (eventType !=
"xcb_generic_event_t")
93 const auto ev =
static_cast<xcb_generic_event_t*
> (msg);
94 if ((ev->response_type & ~0x80) == XCB_PROPERTY_NOTIFY)
95 HandlePropNotify (static_cast<xcb_property_notify_event_t*> (msg));
103 struct IsDoublePtr : std::false_type {};
106 struct IsDoublePtr<T**> : std::true_type {};
124 T** Get (
bool clear =
true)
132 U GetAs (
bool clear =
true)
136 return IsDoublePtr<U>::value ?
137 reinterpret_cast<U
> (&Data_) :
138 reinterpret_cast<U> (Data_);
141 T operator[] (
size_t idx)
const 146 T& operator[] (
size_t idx)
151 operator bool ()
const 153 return Data_ !=
nullptr;
156 bool operator! ()
const 163 void XWrapper::Sync ()
166 XSync (Display_, False);
172 Guarded<Window> data;
175 if (GetRootWinProp (GetAtom (
"_NET_CLIENT_LIST"), &length, data.GetAs<uchar**> ()))
176 for (ulong i = 0; i < length; ++i)
181 QString XWrapper::GetWindowTitle (
Window wid)
188 auto utf8Str = GetAtom (
"UTF8_STRING");
190 if (GetWinProp (wid, GetAtom (
"_NET_WM_VISIBLE_NAME"), &length, data.Get (), utf8Str))
191 name = QString::fromUtf8 (data.GetAs<
char*> (
false));
194 if (GetWinProp (wid, GetAtom (
"_NET_WM_NAME"), &length, data.Get (), utf8Str))
195 name = QString::fromUtf8 (data.GetAs<
char*> (
false));
198 if (GetWinProp (wid, GetAtom (
"XA_WM_NAME"), &length, data.Get (), XA_STRING))
199 name = QString::fromUtf8 (data.GetAs<
char*> (
false));
203 XFetchName (Display_, wid, data.GetAs<
char**> ());
204 name = QString (data.GetAs<
char*> (
false));
210 if (XGetWMName (Display_, wid, &prop))
212 name = QString::fromUtf8 (reinterpret_cast<char*> (prop.value));
220 QIcon XWrapper::GetWindowIcon (
Window wid)
223 ulong type,
count, extra;
226 XGetWindowProperty (Display_, wid, GetAtom (
"_NET_WM_ICON"),
228 &type, &fmt, &
count, &extra,
229 data.GetAs<uchar**> ());
236 auto cur = *data.Get (
false);
237 auto end = cur +
count;
240 QImage img (cur [0], cur [1], QImage::Format_ARGB32);
242 const auto bytesCount = img.sizeInBytes ();
243 for (
int i = 0; i < bytesCount / 4; ++i, ++cur)
244 reinterpret_cast<uint*> (img.bits ()) [i] = *cur;
246 icon.addPixmap (QPixmap::fromImage (img));
252 WinStateFlags XWrapper::GetWindowState (
Window wid)
254 WinStateFlags result;
258 if (!GetWinProp (wid, GetAtom (
"_NET_WM_STATE"),
259 &length, reinterpret_cast<uchar**> (&data), XA_ATOM))
262 for (ulong i = 0; i < length; ++i)
264 const auto curAtom = data [i];
266 auto set = [
this, &curAtom, &result] (
const QString& atom,
WinStateFlag flag)
268 if (curAtom == GetAtom (
"_NET_WM_STATE_" + atom))
291 AllowedActionFlags XWrapper::GetWindowActions (
Window wid)
293 AllowedActionFlags result;
297 if (!GetWinProp (wid, GetAtom (
"_NET_WM_ALLOWED_ACTIONS"),
298 &length, reinterpret_cast<uchar**> (&data), XA_ATOM))
301 for (ulong i = 0; i < length; ++i)
303 const auto curAtom = data [i];
305 auto set = [
this, &curAtom, &result] (
const QString& atom,
AllowedActionFlag flag)
307 if (curAtom == GetAtom (
"_NET_WM_ACTION_" + atom))
332 auto win = GetActiveWindow ();
337 if (!ShouldShow (win) && XGetTransientForHint (Display_, win, &
transient))
347 if (GetWinProp (wid, GetAtom (
"WM_CLASS"), &length, data.Get ()) &&
348 QString (data.GetAs<
char*> (
false)).startsWith (
"leechcraft"))
358 GetAtom (
"_NET_WM_WINDOW_TYPE_DESKTOP"),
359 GetAtom (
"_NET_WM_WINDOW_TYPE_DOCK"),
360 GetAtom (
"_NET_WM_WINDOW_TYPE_TOOLBAR"),
361 GetAtom (
"_NET_WM_WINDOW_TYPE_UTILITY"),
362 GetAtom (
"_NET_WM_WINDOW_TYPE_MENU"),
363 GetAtom (
"_NET_WM_WINDOW_TYPE_SPLASH"),
364 GetAtom (
"_NET_WM_WINDOW_TYPE_POPUP_MENU")
367 for (
const auto& type : GetWindowType (wid))
368 if (ignoreAtoms.contains (type))
375 if (!XGetTransientForHint (Display_, wid, &
transient))
378 if (
transient == 0 ||
transient == wid ||
transient == AppWin_)
381 return !GetWindowType (
transient).contains (GetAtom (
"_NET_WM_WINDOW_TYPE_NORMAL"));
386 if (IsLCWindow (wid))
389 XSelectInput (Display_, wid, PropertyChangeMask);
392 void XWrapper::SetStrut (QWidget *widget, Qt::ToolBarArea area)
394 const auto wid = widget->effectiveWinId ();
396 const auto& winGeom = widget->geometry ();
400 case Qt::BottomToolBarArea:
402 0, 0, 0, winGeom.height (),
406 winGeom.left (), winGeom.right ());
408 case Qt::TopToolBarArea:
410 0, 0, winGeom.height (), 0,
413 winGeom.left (), winGeom.right (),
416 case Qt::LeftToolBarArea:
418 winGeom.width (), 0, 0, 0,
419 winGeom.top (), winGeom.bottom (),
424 case Qt::RightToolBarArea:
426 0, winGeom.width (), 0, 0,
428 winGeom.top (), winGeom.bottom (),
433 qWarning () << Q_FUNC_INFO
434 <<
"incorrect area passed" 440 void XWrapper::ClearStrut (QWidget *w)
442 const auto wid = w->effectiveWinId ();
443 XDeleteProperty (Display_, wid, GetAtom (
"_NET_WM_STRUT"));
444 XDeleteProperty (Display_, wid, GetAtom (
"_NET_WM_STRUT_PARTIAL"));
448 int left,
int right,
int top,
int bottom,
449 int leftStartY,
int leftEndY,
450 int rightStartY,
int rightEndY,
451 int topStartX,
int topEndX,
452 int bottomStartX,
int bottomEndX)
454 ulong struts[12] = { 0 };
461 struts [4] = leftStartY;
462 struts [5] = leftEndY;
463 struts [6] = rightStartY;
464 struts [7] = rightEndY;
465 struts [8] = topStartX;
466 struts [9] = topEndX;
467 struts [10] = bottomStartX;
468 struts [11] = bottomEndX;
470 XChangeProperty (Display_, wid, GetAtom (
"_NET_WM_STRUT_PARTIAL"),
471 XA_CARDINAL, 32, PropModeReplace, reinterpret_cast<uchar*> (struts), 12);
473 XChangeProperty (Display_, wid, GetAtom (
"_NET_WM_STRUT"),
474 XA_CARDINAL, 32, PropModeReplace, reinterpret_cast<uchar*> (struts), 4);
479 SendMessage (wid, GetAtom (
"_NET_ACTIVE_WINDOW"),
SourcePager);
482 void XWrapper::MinimizeWindow (
Window wid)
484 SendMessage (wid, GetAtom (
"WM_CHANGE_STATE"), IconicState);
487 void XWrapper::MaximizeWindow (
Window wid)
489 SendMessage (wid, GetAtom (
"_NET_WM_STATE"),
StateAdd,
490 GetAtom (
"_NET_WM_STATE_MAXIMIZED_VERT"),
491 GetAtom (
"_NET_WM_STATE_MAXIMIZED_HORZ"),
495 void XWrapper::UnmaximizeWindow (
Window wid)
497 SendMessage (wid, GetAtom (
"_NET_WM_STATE"),
StateRemove,
498 GetAtom (
"_NET_WM_STATE_MAXIMIZED_VERT"),
499 GetAtom (
"_NET_WM_STATE_MAXIMIZED_HORZ"),
503 void XWrapper::ResizeWindow (
Window wid,
int width,
int height)
505 XResizeWindow (Display_, wid, width, height);
510 SendMessage (wid, GetAtom (
"_NET_WM_STATE"),
514 void XWrapper::UnshadeWindow (
Window wid)
516 SendMessage (wid, GetAtom (
"_NET_WM_STATE"),
525 SendMessage (wid, GetAtom (
"_NET_WM_STATE"), top,
528 SendMessage (wid, GetAtom (
"_NET_WM_STATE"), bottom,
534 SendMessage (wid, GetAtom (
"_NET_CLOSE_WINDOW"), 0,
SourcePager);
538 void XWrapper::HandlePropNotify (T ev)
540 if (ev->state == XCB_PROPERTY_DELETE)
543 const auto wid = ev->window;
547 if (ev->atom == GetAtom (
"_NET_CLIENT_LIST"))
548 emit windowListChanged ();
549 else if (ev->atom == GetAtom (
"_NET_ACTIVE_WINDOW"))
550 emit activeWindowChanged ();
551 else if (ev->atom == GetAtom (
"_NET_CURRENT_DESKTOP"))
552 emit desktopChanged ();
556 if (ev->atom == GetAtom (
"_NET_WM_VISIBLE_NAME") ||
557 ev->atom == GetAtom (
"WM_NAME"))
558 emit windowNameChanged (wid);
559 else if (ev->atom == GetAtom (
"_NET_WM_ICON"))
560 emit windowIconChanged (wid);
561 else if (ev->atom == GetAtom (
"_NET_WM_DESKTOP"))
562 emit windowDesktopChanged (wid);
563 else if (ev->atom == GetAtom (
"_NET_WM_STATE"))
564 emit windowStateChanged (wid);
565 else if (ev->atom == GetAtom (
"_NET_WM_ALLOWED_ACTIONS"))
566 emit windowActionsChanged (wid);
570 Window XWrapper::GetActiveWindow ()
575 if (!GetRootWinProp (GetAtom (
"_NET_ACTIVE_WINDOW"), &length, data.GetAs<uchar**> (), XA_WINDOW))
584 int XWrapper::GetDesktopCount ()
589 if (GetRootWinProp (GetAtom (
"_NET_NUMBER_OF_DESKTOPS"), &length, data.GetAs<uchar**> (), XA_CARDINAL))
590 return length > 0 ? data [0] : -1;
595 int XWrapper::GetCurrentDesktop ()
600 if (GetRootWinProp (GetAtom (
"_NET_CURRENT_DESKTOP"), &length, data.GetAs<uchar**> (), XA_CARDINAL))
601 return length > 0 ? data [0] : -1;
606 void XWrapper::SetCurrentDesktop (
int desktop)
608 SendMessage (AppWin_, GetAtom (
"_NET_CURRENT_DESKTOP"), desktop);
611 QStringList XWrapper::GetDesktopNames ()
616 if (!GetRootWinProp (GetAtom (
"_NET_DESKTOP_NAMES"),
617 &length, data.GetAs<uchar**> (), GetAtom (
"UTF8_STRING")))
624 for (
char *pos = data.GetAs<
char*> (
false), *end = data.GetAs<
char*> (
false) + length; pos < end; )
626 const auto& str = QString::fromUtf8 (pos);
628 pos += str.toUtf8 ().size () + 1;
633 QString XWrapper::GetDesktopName (
int desktop,
const QString& def)
635 return GetDesktopNames ().value (desktop, def);
638 int XWrapper::GetWindowDesktop (
Window wid)
642 if (GetWinProp (wid, GetAtom (
"_NET_WM_DESKTOP"), &length, data.GetAs<uchar**> (), XA_CARDINAL) && length)
645 if (GetWinProp (wid, GetAtom (
"_WIN_WORKSPACE"), &length, data.GetAs<uchar**> (), XA_CARDINAL) && length)
651 void XWrapper::MoveWindowToDesktop (
Window wid,
int num)
653 unsigned long data = num;
654 XChangeProperty (QX11Info::display (),
656 GetAtom (
"_NET_WM_DESKTOP"),
660 reinterpret_cast<unsigned char*> (&data),
664 QRect XWrapper::GetAvailableGeometry (
int screenIdx)
666 auto dw = QApplication::desktop ();
668 const auto& screens = QGuiApplication::screens ();
669 auto screen = screens.value (screenIdx, QGuiApplication::primaryScreen ());
671 auto available = screen->geometry ();
672 const auto deskGeom = dw->rect ();
674 for (
const auto wid : GetWindows ())
677 Guarded<ulong> struts;
678 const auto status = GetWinProp (wid, GetAtom (
"_NET_WM_STRUT_PARTIAL"),
679 &length, struts.GetAs<uchar**> (), XA_CARDINAL);
680 if (!status || length != 12)
685 static_cast<int> (deskGeom.x ()),
686 static_cast<int> (deskGeom.y () + struts [4]),
687 static_cast<int> (struts [0]),
688 static_cast<int> (struts [5] - struts [4])
690 if (available.intersects (left))
691 available.setX (left.width ());
695 static_cast<int> (deskGeom.x () + deskGeom.width () - struts [1]),
696 static_cast<int> (deskGeom.y () + struts [6]),
697 static_cast<int> (struts [1]),
698 static_cast<int> (struts [7] - struts [6])
700 if (available.intersects (right))
701 available.setWidth (right.x () - available.x ());
705 static_cast<int> (deskGeom.x () + struts [8]),
706 static_cast<int> (deskGeom.y ()),
707 static_cast<int> (struts [9] - struts [8]),
708 static_cast<int> (struts [2])
710 if (available.intersects (top))
711 available.setY (top.height ());
715 static_cast<int> (deskGeom.x () + struts [10]),
716 static_cast<int> (deskGeom.y () + deskGeom.height () - struts [3]),
717 static_cast<int> (struts [11] - struts [10]),
718 static_cast<int> (struts [3])
720 if (available.intersects (bottom))
721 available.setHeight (bottom.y () - available.y ());
727 QRect XWrapper::GetAvailableGeometry (QWidget *widget)
729 return GetAvailableGeometry (QApplication::desktop ()->screenNumber (widget));
732 Atom XWrapper::GetAtom (
const QString& name)
734 if (Atoms_.contains (name))
735 return Atoms_ [name];
737 auto atom = XInternAtom (Display_, name.toLocal8Bit (),
false);
738 Atoms_ [name] = atom;
742 bool XWrapper::GetWinProp (
Window win, Atom property,
743 ulong *length,
unsigned char **result, Atom req)
const 746 ulong type = 0, rest = 0;
747 return XGetWindowProperty (Display_, win,
748 property, 0, 1024,
false, req, &type,
749 &fmt, length, &rest, result) == Success;
752 bool XWrapper::GetRootWinProp (Atom property,
753 ulong *length, uchar **result, Atom req)
const 755 return GetWinProp (AppWin_, property, length, result, req);
763 ulong *data =
nullptr;
765 if (!GetWinProp (wid, GetAtom (
"_NET_WM_WINDOW_TYPE"),
766 &length, reinterpret_cast<uchar**> (&data)))
769 for (ulong i = 0; i < length; ++i)
776 bool XWrapper::SendMessage (
Window wid, Atom atom, ulong d0, ulong d1, ulong d2, ulong d3, ulong d4)
779 msg.xclient.window = wid;
780 msg.xclient.type = ClientMessage;
781 msg.xclient.message_type = atom;
782 msg.xclient.send_event =
true;
783 msg.xclient.display = Display_;
784 msg.xclient.format = 32;
785 msg.xclient.data.l [0] = d0;
786 msg.xclient.data.l [1] = d1;
787 msg.xclient.data.l [2] = d2;
788 msg.xclient.data.l [3] = d3;
789 msg.xclient.data.l [4] = d4;
791 auto flags = SubstructureRedirectMask | SubstructureNotifyMask;
792 return XSendEvent (Display_, AppWin_,
false, flags, &msg) == Success;
795 void XWrapper::initialize ()
constexpr detail::AggregateType< detail::AggregateFunction::Count, Ptr > count
constexpr detail::AggregateType< detail::AggregateFunction::Max, Ptr > max