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"),
227 0, std::numeric_limits<long>::max (), False, AnyPropertyType,
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 for (
int i = 0; i < img.byteCount () / 4; ++i, ++cur)
243 reinterpret_cast<uint*> (img.bits ()) [i] = *cur;
245 icon.addPixmap (QPixmap::fromImage (img));
251 WinStateFlags XWrapper::GetWindowState (
Window wid)
253 WinStateFlags result;
257 if (!GetWinProp (wid, GetAtom (
"_NET_WM_STATE"),
258 &length, reinterpret_cast<uchar**> (&data), XA_ATOM))
261 for (ulong i = 0; i < length; ++i)
263 const auto curAtom = data [i];
265 auto set = [
this, &curAtom, &result] (
const QString& atom,
WinStateFlag flag)
267 if (curAtom == GetAtom (
"_NET_WM_STATE_" + atom))
290 AllowedActionFlags XWrapper::GetWindowActions (
Window wid)
292 AllowedActionFlags result;
296 if (!GetWinProp (wid, GetAtom (
"_NET_WM_ALLOWED_ACTIONS"),
297 &length, reinterpret_cast<uchar**> (&data), XA_ATOM))
300 for (ulong i = 0; i < length; ++i)
302 const auto curAtom = data [i];
304 auto set = [
this, &curAtom, &result] (
const QString& atom,
AllowedActionFlag flag)
306 if (curAtom == GetAtom (
"_NET_WM_ACTION_" + atom))
331 auto win = GetActiveWindow ();
336 if (!ShouldShow (win) && XGetTransientForHint (Display_, win, &
transient))
346 if (GetWinProp (wid, GetAtom (
"WM_CLASS"), &length, data.Get ()) &&
347 QString (data.GetAs<
char*> (
false)).startsWith (
"leechcraft"))
357 GetAtom (
"_NET_WM_WINDOW_TYPE_DESKTOP"),
358 GetAtom (
"_NET_WM_WINDOW_TYPE_DOCK"),
359 GetAtom (
"_NET_WM_WINDOW_TYPE_TOOLBAR"),
360 GetAtom (
"_NET_WM_WINDOW_TYPE_UTILITY"),
361 GetAtom (
"_NET_WM_WINDOW_TYPE_MENU"),
362 GetAtom (
"_NET_WM_WINDOW_TYPE_SPLASH"),
363 GetAtom (
"_NET_WM_WINDOW_TYPE_POPUP_MENU")
366 for (
const auto& type : GetWindowType (wid))
367 if (ignoreAtoms.contains (type))
374 if (!XGetTransientForHint (Display_, wid, &
transient))
377 if (
transient == 0 ||
transient == wid ||
transient == AppWin_)
380 return !GetWindowType (
transient).contains (GetAtom (
"_NET_WM_WINDOW_TYPE_NORMAL"));
385 if (IsLCWindow (wid))
388 XSelectInput (Display_, wid, PropertyChangeMask);
391 void XWrapper::SetStrut (QWidget *widget, Qt::ToolBarArea area)
393 const auto wid = widget->effectiveWinId ();
395 const auto& winGeom = widget->geometry ();
399 case Qt::BottomToolBarArea:
401 0, 0, 0, winGeom.height (),
405 winGeom.left (), winGeom.right ());
407 case Qt::TopToolBarArea:
409 0, 0, winGeom.height (), 0,
412 winGeom.left (), winGeom.right (),
415 case Qt::LeftToolBarArea:
417 winGeom.width (), 0, 0, 0,
418 winGeom.top (), winGeom.bottom (),
423 case Qt::RightToolBarArea:
425 0, winGeom.width (), 0, 0,
427 winGeom.top (), winGeom.bottom (),
432 qWarning () << Q_FUNC_INFO
433 <<
"incorrect area passed" 439 void XWrapper::ClearStrut (QWidget *w)
441 const auto wid = w->effectiveWinId ();
442 XDeleteProperty (Display_, wid, GetAtom (
"_NET_WM_STRUT"));
443 XDeleteProperty (Display_, wid, GetAtom (
"_NET_WM_STRUT_PARTIAL"));
447 int left,
int right,
int top,
int bottom,
448 int leftStartY,
int leftEndY,
449 int rightStartY,
int rightEndY,
450 int topStartX,
int topEndX,
451 int bottomStartX,
int bottomEndX)
453 ulong struts[12] = { 0 };
460 struts [4] = leftStartY;
461 struts [5] = leftEndY;
462 struts [6] = rightStartY;
463 struts [7] = rightEndY;
464 struts [8] = topStartX;
465 struts [9] = topEndX;
466 struts [10] = bottomStartX;
467 struts [11] = bottomEndX;
469 XChangeProperty (Display_, wid, GetAtom (
"_NET_WM_STRUT_PARTIAL"),
470 XA_CARDINAL, 32, PropModeReplace, reinterpret_cast<uchar*> (struts), 12);
472 XChangeProperty (Display_, wid, GetAtom (
"_NET_WM_STRUT"),
473 XA_CARDINAL, 32, PropModeReplace, reinterpret_cast<uchar*> (struts), 4);
478 SendMessage (wid, GetAtom (
"_NET_ACTIVE_WINDOW"),
SourcePager);
481 void XWrapper::MinimizeWindow (
Window wid)
483 SendMessage (wid, GetAtom (
"WM_CHANGE_STATE"), IconicState);
486 void XWrapper::MaximizeWindow (
Window wid)
488 SendMessage (wid, GetAtom (
"_NET_WM_STATE"),
StateAdd,
489 GetAtom (
"_NET_WM_STATE_MAXIMIZED_VERT"),
490 GetAtom (
"_NET_WM_STATE_MAXIMIZED_HORZ"),
494 void XWrapper::UnmaximizeWindow (
Window wid)
496 SendMessage (wid, GetAtom (
"_NET_WM_STATE"),
StateRemove,
497 GetAtom (
"_NET_WM_STATE_MAXIMIZED_VERT"),
498 GetAtom (
"_NET_WM_STATE_MAXIMIZED_HORZ"),
502 void XWrapper::ResizeWindow (
Window wid,
int width,
int height)
504 XResizeWindow (Display_, wid, width, height);
509 SendMessage (wid, GetAtom (
"_NET_WM_STATE"),
513 void XWrapper::UnshadeWindow (
Window wid)
515 SendMessage (wid, GetAtom (
"_NET_WM_STATE"),
524 SendMessage (wid, GetAtom (
"_NET_WM_STATE"), top,
527 SendMessage (wid, GetAtom (
"_NET_WM_STATE"), bottom,
533 SendMessage (wid, GetAtom (
"_NET_CLOSE_WINDOW"), 0,
SourcePager);
537 void XWrapper::HandlePropNotify (T ev)
539 if (ev->state == XCB_PROPERTY_DELETE)
542 const auto wid = ev->window;
546 if (ev->atom == GetAtom (
"_NET_CLIENT_LIST"))
547 emit windowListChanged ();
548 else if (ev->atom == GetAtom (
"_NET_ACTIVE_WINDOW"))
549 emit activeWindowChanged ();
550 else if (ev->atom == GetAtom (
"_NET_CURRENT_DESKTOP"))
551 emit desktopChanged ();
555 if (ev->atom == GetAtom (
"_NET_WM_VISIBLE_NAME") ||
556 ev->atom == GetAtom (
"WM_NAME"))
557 emit windowNameChanged (wid);
558 else if (ev->atom == GetAtom (
"_NET_WM_ICON"))
559 emit windowIconChanged (wid);
560 else if (ev->atom == GetAtom (
"_NET_WM_DESKTOP"))
561 emit windowDesktopChanged (wid);
562 else if (ev->atom == GetAtom (
"_NET_WM_STATE"))
563 emit windowStateChanged (wid);
564 else if (ev->atom == GetAtom (
"_NET_WM_ALLOWED_ACTIONS"))
565 emit windowActionsChanged (wid);
569 Window XWrapper::GetActiveWindow ()
574 if (!GetRootWinProp (GetAtom (
"_NET_ACTIVE_WINDOW"), &length, data.GetAs<uchar**> (), XA_WINDOW))
583 int XWrapper::GetDesktopCount ()
588 if (GetRootWinProp (GetAtom (
"_NET_NUMBER_OF_DESKTOPS"), &length, data.GetAs<uchar**> (), XA_CARDINAL))
589 return length > 0 ? data [0] : -1;
594 int XWrapper::GetCurrentDesktop ()
599 if (GetRootWinProp (GetAtom (
"_NET_CURRENT_DESKTOP"), &length, data.GetAs<uchar**> (), XA_CARDINAL))
600 return length > 0 ? data [0] : -1;
605 void XWrapper::SetCurrentDesktop (
int desktop)
607 SendMessage (AppWin_, GetAtom (
"_NET_CURRENT_DESKTOP"), desktop);
610 QStringList XWrapper::GetDesktopNames ()
615 if (!GetRootWinProp (GetAtom (
"_NET_DESKTOP_NAMES"),
616 &length, data.GetAs<uchar**> (), GetAtom (
"UTF8_STRING")))
623 for (
char *
pos = data.GetAs<
char*> (
false), *end = data.GetAs<
char*> (
false) + length;
pos < end; )
625 const auto& str = QString::fromUtf8 (
pos);
627 pos += str.toUtf8 ().size () + 1;
632 QString XWrapper::GetDesktopName (
int desktop,
const QString& def)
634 return GetDesktopNames ().value (desktop, def);
637 int XWrapper::GetWindowDesktop (
Window wid)
641 if (GetWinProp (wid, GetAtom (
"_NET_WM_DESKTOP"), &length, data.GetAs<uchar**> (), XA_CARDINAL) && length)
644 if (GetWinProp (wid, GetAtom (
"_WIN_WORKSPACE"), &length, data.GetAs<uchar**> (), XA_CARDINAL) && length)
650 void XWrapper::MoveWindowToDesktop (
Window wid,
int num)
652 unsigned long data = num;
653 XChangeProperty (QX11Info::display (),
655 GetAtom (
"_NET_WM_DESKTOP"),
659 reinterpret_cast<unsigned char*> (&data),
663 QRect XWrapper::GetAvailableGeometry (
int screen)
665 auto dw = QApplication::desktop ();
667 if (screen < 0 || screen >= dw->screenCount ())
668 screen = dw->primaryScreen ();
670 if (dw->isVirtualDesktop ())
671 screen = DefaultScreen (Display_);
673 auto available = dw->screenGeometry (screen);
674 const auto deskGeom = dw->rect ();
676 for (
const auto wid : GetWindows ())
679 Guarded<ulong> struts;
680 const auto status = GetWinProp (wid, GetAtom (
"_NET_WM_STRUT_PARTIAL"),
681 &length, struts.GetAs<uchar**> (), XA_CARDINAL);
682 if (!status || length != 12)
687 static_cast<int> (deskGeom.x ()),
688 static_cast<int> (deskGeom.y () + struts [4]),
689 static_cast<int> (struts [0]),
690 static_cast<int> (struts [5] - struts [4])
692 if (available.intersects (left))
693 available.setX (left.width ());
697 static_cast<int> (deskGeom.x () + deskGeom.width () - struts [1]),
698 static_cast<int> (deskGeom.y () + struts [6]),
699 static_cast<int> (struts [1]),
700 static_cast<int> (struts [7] - struts [6])
702 if (available.intersects (right))
703 available.setWidth (right.x () - available.x ());
707 static_cast<int> (deskGeom.x () + struts [8]),
708 static_cast<int> (deskGeom.y ()),
709 static_cast<int> (struts [9] - struts [8]),
710 static_cast<int> (struts [2])
712 if (available.intersects (top))
713 available.setY (top.height ());
717 static_cast<int> (deskGeom.x () + struts [10]),
718 static_cast<int> (deskGeom.y () + deskGeom.height () - struts [3]),
719 static_cast<int> (struts [11] - struts [10]),
720 static_cast<int> (struts [3])
722 if (available.intersects (bottom))
723 available.setHeight (bottom.y () - available.y ());
729 QRect XWrapper::GetAvailableGeometry (QWidget *widget)
731 return GetAvailableGeometry (QApplication::desktop ()->screenNumber (widget));
734 Atom XWrapper::GetAtom (
const QString& name)
736 if (Atoms_.contains (name))
737 return Atoms_ [name];
739 auto atom = XInternAtom (Display_, name.toLocal8Bit (),
false);
740 Atoms_ [name] = atom;
744 bool XWrapper::GetWinProp (
Window win, Atom property,
745 ulong *length,
unsigned char **result, Atom req)
const 748 ulong type = 0, rest = 0;
749 return XGetWindowProperty (Display_, win,
750 property, 0, 1024,
false, req, &type,
751 &fmt, length, &rest, result) == Success;
754 bool XWrapper::GetRootWinProp (Atom property,
755 ulong *length, uchar **result, Atom req)
const 757 return GetWinProp (AppWin_, property, length, result, req);
765 ulong *data =
nullptr;
767 if (!GetWinProp (wid, GetAtom (
"_NET_WM_WINDOW_TYPE"),
768 &length, reinterpret_cast<uchar**> (&data)))
771 for (ulong i = 0; i < length; ++i)
778 bool XWrapper::SendMessage (
Window wid, Atom atom, ulong d0, ulong d1, ulong d2, ulong d3, ulong d4)
781 msg.xclient.window = wid;
782 msg.xclient.type = ClientMessage;
783 msg.xclient.message_type = atom;
784 msg.xclient.send_event =
true;
785 msg.xclient.display = Display_;
786 msg.xclient.format = 32;
787 msg.xclient.data.l [0] = d0;
788 msg.xclient.data.l [1] = d1;
789 msg.xclient.data.l [2] = d2;
790 msg.xclient.data.l [3] = d3;
791 msg.xclient.data.l [4] = d4;
793 auto flags = SubstructureRedirectMask | SubstructureNotifyMask;
794 return XSendEvent (Display_, AppWin_,
false, flags, &msg) == Success;
797 void XWrapper::initialize ()
constexpr detail::AggregateType< detail::AggregateFunction::Count > count
detail::ExprTree< detail::ExprType::LeafStaticPlaceholder, boost::mpl::int_< Idx > > pos