32 #include <type_traits>
36 #include <QApplication>
38 #include <QDesktopWidget>
39 #include <QAbstractEventDispatcher>
43 #include <X11/Xutil.h>
44 #include <X11/Xatom.h>
46 #if QT_VERSION >= 0x050000
61 #if QT_VERSION < 0x050000
62 bool EvFilter (
void *msg)
71 , AppWin_ (QX11Info::appRootWindow ())
72 #if QT_VERSION < 0x050000
73 , PrevFilter_ (QAbstractEventDispatcher::instance ()->setEventFilter (EvFilter))
76 #if QT_VERSION >= 0x050000
77 QAbstractEventDispatcher::instance ()->installNativeEventFilter (
this);
80 #if QT_VERSION < 0x050000
83 PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask);
85 const uint32_t rootEvents [] =
87 XCB_EVENT_MASK_STRUCTURE_NOTIFY |
88 XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
89 XCB_EVENT_MASK_PROPERTY_CHANGE
91 xcb_change_window_attributes (QX11Info::connection (),
92 AppWin_, XCB_CW_EVENT_MASK, rootEvents);
102 Display* XWrapper::GetDisplay ()
const
112 #if QT_VERSION < 0x050000
115 if (ev->type == PropertyNotify)
116 HandlePropNotify (&ev->xproperty);
118 return PrevFilter_ ? PrevFilter_ (ev) :
false;
121 bool XWrapper::nativeEventFilter (
const QByteArray& eventType,
void *msg,
long int*)
123 if (eventType !=
"xcb_generic_event_t")
126 const auto ev =
static_cast<xcb_generic_event_t*
> (msg);
127 if ((ev->response_type & ~0x80) == XCB_PROPERTY_NOTIFY)
128 HandlePropNotify (static_cast<xcb_property_notify_event_t*> (msg));
137 struct IsDoublePtr : std::false_type {};
140 struct IsDoublePtr<T**> : std::true_type {};
158 T** Get (
bool clear =
true)
166 U GetAs (
bool clear =
true)
170 return IsDoublePtr<U>::value ?
171 reinterpret_cast<U
> (&
Data_) :
172 reinterpret_cast<U> (
Data_);
175 T operator[] (
size_t idx)
const
180 T& operator[] (
size_t idx)
185 operator bool ()
const
187 return Data_ !=
nullptr;
190 bool operator! ()
const
197 void XWrapper::Sync ()
206 Guarded<Window> data;
209 if (GetRootWinProp (GetAtom (
"_NET_CLIENT_LIST"), &length, data.GetAs<uchar**> ()))
210 for (ulong i = 0; i < length; ++i)
215 QString XWrapper::GetWindowTitle (
Window wid)
222 auto utf8Str = GetAtom (
"UTF8_STRING");
224 if (GetWinProp (wid, GetAtom (
"_NET_WM_VISIBLE_NAME"), &length, data.Get (), utf8Str))
225 name = QString::fromUtf8 (data.GetAs<
char*> (
false));
228 if (GetWinProp (wid, GetAtom (
"_NET_WM_NAME"), &length, data.Get (), utf8Str))
229 name = QString::fromUtf8 (data.GetAs<
char*> (
false));
232 if (GetWinProp (wid, GetAtom (
"XA_WM_NAME"), &length, data.Get (), XA_STRING))
233 name = QString::fromUtf8 (data.GetAs<
char*> (
false));
237 XFetchName (
Display_, wid, data.GetAs<
char**> ());
238 name = QString (data.GetAs<
char*> (
false));
244 if (XGetWMName (
Display_, wid, &prop))
246 name = QString::fromUtf8 (reinterpret_cast<char*> (prop.value));
254 QIcon XWrapper::GetWindowIcon (
Window wid)
257 ulong type, count, extra;
260 XGetWindowProperty (
Display_, wid, GetAtom (
"_NET_WM_ICON"),
261 0, std::numeric_limits<long>::max (), False, AnyPropertyType,
262 &type, &fmt, &count, &extra,
263 data.GetAs<uchar**> ());
270 auto cur = *data.Get (
false);
271 auto end = cur + count;
274 QImage img (cur [0], cur [1], QImage::Format_ARGB32);
276 for (
int i = 0; i < img.byteCount () / 4; ++i, ++cur)
277 reinterpret_cast<uint*> (img.bits ()) [i] = *cur;
279 icon.addPixmap (QPixmap::fromImage (img));
285 WinStateFlags XWrapper::GetWindowState (
Window wid)
287 WinStateFlags result;
291 if (!GetWinProp (wid, GetAtom (
"_NET_WM_STATE"),
292 &length, reinterpret_cast<uchar**> (&data), XA_ATOM))
295 for (ulong i = 0; i < length; ++i)
297 const auto curAtom = data [i];
299 auto set = [
this, &curAtom, &result] (
const QString& atom,
WinStateFlag flag)
301 if (curAtom == GetAtom (
"_NET_WM_STATE_" + atom))
324 AllowedActionFlags XWrapper::GetWindowActions (
Window wid)
326 AllowedActionFlags result;
330 if (!GetWinProp (wid, GetAtom (
"_NET_WM_ALLOWED_ACTIONS"),
331 &length, reinterpret_cast<uchar**> (&data), XA_ATOM))
334 for (ulong i = 0; i < length; ++i)
336 const auto curAtom = data [i];
338 auto set = [
this, &curAtom, &result] (
const QString& atom,
AllowedActionFlag flag)
340 if (curAtom == GetAtom (
"_NET_WM_ACTION_" + atom))
365 auto win = GetActiveWindow ();
370 if (!ShouldShow (win) && XGetTransientForHint (
Display_, win, &
transient))
380 if (GetWinProp (wid, GetAtom (
"WM_CLASS"), &length, data.Get ()) &&
381 QString (data.GetAs<
char*> (
false)).startsWith (
"leechcraft"))
391 GetAtom (
"_NET_WM_WINDOW_TYPE_DESKTOP"),
392 GetAtom (
"_NET_WM_WINDOW_TYPE_DOCK"),
393 GetAtom (
"_NET_WM_WINDOW_TYPE_TOOLBAR"),
394 GetAtom (
"_NET_WM_WINDOW_TYPE_UTILITY"),
395 GetAtom (
"_NET_WM_WINDOW_TYPE_MENU"),
396 GetAtom (
"_NET_WM_WINDOW_TYPE_SPLASH"),
397 GetAtom (
"_NET_WM_WINDOW_TYPE_POPUP_MENU")
400 for (
const auto& type : GetWindowType (wid))
401 if (ignoreAtoms.contains (type))
408 if (!XGetTransientForHint (
Display_, wid, &
transient))
411 if (
transient == 0 ||
transient == wid ||
transient == AppWin_)
414 return !GetWindowType (
transient).contains (GetAtom (
"_NET_WM_WINDOW_TYPE_NORMAL"));
419 if (IsLCWindow (wid))
422 XSelectInput (
Display_, wid, PropertyChangeMask);
425 void XWrapper::SetStrut (QWidget *widget, Qt::ToolBarArea area)
427 const auto wid = widget->effectiveWinId ();
429 const auto& winGeom = widget->geometry ();
433 case Qt::BottomToolBarArea:
435 0, 0, 0, winGeom.height (),
439 winGeom.left (), winGeom.right ());
441 case Qt::TopToolBarArea:
443 0, 0, winGeom.height (), 0,
446 winGeom.left (), winGeom.right (),
449 case Qt::LeftToolBarArea:
451 winGeom.width (), 0, 0, 0,
452 winGeom.top (), winGeom.bottom (),
457 case Qt::RightToolBarArea:
459 0, winGeom.width (), 0, 0,
461 winGeom.top (), winGeom.bottom (),
466 qWarning () << Q_FUNC_INFO
467 <<
"incorrect area passed"
473 void XWrapper::ClearStrut (QWidget *w)
475 const auto wid = w->effectiveWinId ();
476 XDeleteProperty (
Display_, wid, GetAtom (
"_NET_WM_STRUT"));
477 XDeleteProperty (
Display_, wid, GetAtom (
"_NET_WM_STRUT_PARTIAL"));
481 int left,
int right,
int top,
int bottom,
482 int leftStartY,
int leftEndY,
483 int rightStartY,
int rightEndY,
484 int topStartX,
int topEndX,
485 int bottomStartX,
int bottomEndX)
487 ulong struts[12] = { 0 };
494 struts [4] = leftStartY;
495 struts [5] = leftEndY;
496 struts [6] = rightStartY;
497 struts [7] = rightEndY;
498 struts [8] = topStartX;
499 struts [9] = topEndX;
500 struts [10] = bottomStartX;
501 struts [11] = bottomEndX;
503 XChangeProperty (
Display_, wid, GetAtom (
"_NET_WM_STRUT_PARTIAL"),
504 XA_CARDINAL, 32, PropModeReplace, reinterpret_cast<uchar*> (struts), 12);
506 XChangeProperty (
Display_, wid, GetAtom (
"_NET_WM_STRUT"),
507 XA_CARDINAL, 32, PropModeReplace, reinterpret_cast<uchar*> (struts), 4);
512 SendMessage (wid, GetAtom (
"_NET_ACTIVE_WINDOW"),
SourcePager);
515 void XWrapper::MinimizeWindow (
Window wid)
517 SendMessage (wid, GetAtom (
"WM_CHANGE_STATE"), IconicState);
520 void XWrapper::MaximizeWindow (
Window wid)
522 SendMessage (wid, GetAtom (
"_NET_WM_STATE"),
StateAdd,
523 GetAtom (
"_NET_WM_STATE_MAXIMIZED_VERT"),
524 GetAtom (
"_NET_WM_STATE_MAXIMIZED_HORZ"),
528 void XWrapper::UnmaximizeWindow (
Window wid)
530 SendMessage (wid, GetAtom (
"_NET_WM_STATE"),
StateRemove,
531 GetAtom (
"_NET_WM_STATE_MAXIMIZED_VERT"),
532 GetAtom (
"_NET_WM_STATE_MAXIMIZED_HORZ"),
536 void XWrapper::ResizeWindow (
Window wid,
int width,
int height)
538 XResizeWindow (
Display_, wid, width, height);
543 SendMessage (wid, GetAtom (
"_NET_WM_STATE"),
547 void XWrapper::UnshadeWindow (
Window wid)
549 SendMessage (wid, GetAtom (
"_NET_WM_STATE"),
558 SendMessage (wid, GetAtom (
"_NET_WM_STATE"), top,
561 SendMessage (wid, GetAtom (
"_NET_WM_STATE"), bottom,
567 SendMessage (wid, GetAtom (
"_NET_CLOSE_WINDOW"), 0,
SourcePager);
570 #if QT_VERSION < 0x050000
572 void XWrapper::HandlePropNotify (T ev)
574 if (ev->state == PropertyDelete)
577 const auto wid = ev->window;
581 if (ev->atom == GetAtom (
"_NET_CLIENT_LIST"))
582 emit windowListChanged ();
583 else if (ev->atom == GetAtom (
"_NET_ACTIVE_WINDOW"))
584 emit activeWindowChanged ();
585 else if (ev->atom == GetAtom (
"_NET_CURRENT_DESKTOP"))
586 emit desktopChanged ();
590 if (ev->atom == GetAtom (
"_NET_WM_VISIBLE_NAME") ||
591 ev->atom == GetAtom (
"WM_NAME"))
592 emit windowNameChanged (wid);
593 else if (ev->atom == GetAtom (
"_NET_WM_ICON"))
594 emit windowIconChanged (wid);
595 else if (ev->atom == GetAtom (
"_NET_WM_DESKTOP"))
596 emit windowDesktopChanged (wid);
597 else if (ev->atom == GetAtom (
"_NET_WM_STATE"))
598 emit windowStateChanged (wid);
599 else if (ev->atom == GetAtom (
"_NET_WM_ALLOWED_ACTIONS"))
600 emit windowActionsChanged (wid);
605 void XWrapper::HandlePropNotify (T ev)
607 if (ev->state == XCB_PROPERTY_DELETE)
610 const auto wid = ev->window;
614 if (ev->atom == GetAtom (
"_NET_CLIENT_LIST"))
615 emit windowListChanged ();
616 else if (ev->atom == GetAtom (
"_NET_ACTIVE_WINDOW"))
617 emit activeWindowChanged ();
618 else if (ev->atom == GetAtom (
"_NET_CURRENT_DESKTOP"))
619 emit desktopChanged ();
623 if (ev->atom == GetAtom (
"_NET_WM_VISIBLE_NAME") ||
624 ev->atom == GetAtom (
"WM_NAME"))
625 emit windowNameChanged (wid);
626 else if (ev->atom == GetAtom (
"_NET_WM_ICON"))
627 emit windowIconChanged (wid);
628 else if (ev->atom == GetAtom (
"_NET_WM_DESKTOP"))
629 emit windowDesktopChanged (wid);
630 else if (ev->atom == GetAtom (
"_NET_WM_STATE"))
631 emit windowStateChanged (wid);
632 else if (ev->atom == GetAtom (
"_NET_WM_ALLOWED_ACTIONS"))
633 emit windowActionsChanged (wid);
638 Window XWrapper::GetActiveWindow ()
643 if (!GetRootWinProp (GetAtom (
"_NET_ACTIVE_WINDOW"), &length, data.GetAs<uchar**> (), XA_WINDOW))
652 int XWrapper::GetDesktopCount ()
657 if (GetRootWinProp (GetAtom (
"_NET_NUMBER_OF_DESKTOPS"), &length, data.GetAs<uchar**> (), XA_CARDINAL))
658 return length > 0 ? data [0] : -1;
663 int XWrapper::GetCurrentDesktop ()
668 if (GetRootWinProp (GetAtom (
"_NET_CURRENT_DESKTOP"), &length, data.GetAs<uchar**> (), XA_CARDINAL))
669 return length > 0 ? data [0] : -1;
674 void XWrapper::SetCurrentDesktop (
int desktop)
676 SendMessage (AppWin_, GetAtom (
"_NET_CURRENT_DESKTOP"), desktop);
679 QStringList XWrapper::GetDesktopNames ()
684 if (!GetRootWinProp (GetAtom (
"_NET_DESKTOP_NAMES"),
685 &length, data.GetAs<uchar**> (), GetAtom (
"UTF8_STRING")))
692 for (
char *
pos = data.GetAs<
char*> (
false), *end = data.GetAs<
char*> (
false) + length;
pos < end; )
694 const auto& str = QString::fromUtf8 (
pos);
696 pos += str.toUtf8 ().size () + 1;
701 QString XWrapper::GetDesktopName (
int desktop,
const QString& def)
703 return GetDesktopNames ().value (desktop, def);
706 int XWrapper::GetWindowDesktop (
Window wid)
710 if (GetWinProp (wid, GetAtom (
"_NET_WM_DESKTOP"), &length, data.GetAs<uchar**> (), XA_CARDINAL) && length)
713 if (GetWinProp (wid, GetAtom (
"_WIN_WORKSPACE"), &length, data.GetAs<uchar**> (), XA_CARDINAL) && length)
719 void XWrapper::MoveWindowToDesktop (
Window wid,
int num)
721 #if QT_VERSION < 0x050000
722 SendMessage (wid, GetAtom (
"_NET_WM_DESKTOP"), num);
724 unsigned long data = num;
725 XChangeProperty (QX11Info::display (),
727 GetAtom (
"_NET_WM_DESKTOP"),
731 reinterpret_cast<unsigned char*> (&data),
736 QRect XWrapper::GetAvailableGeometry (
int screen)
738 auto dw = QApplication::desktop ();
740 if (screen < 0 || screen >= dw->screenCount ())
741 screen = dw->primaryScreen ();
743 if (dw->isVirtualDesktop ())
746 auto available = dw->screenGeometry (screen);
747 const auto deskGeom = dw->rect ();
749 for (
const auto wid : GetWindows ())
752 Guarded<ulong> struts;
753 const auto status = GetWinProp (wid, GetAtom (
"_NET_WM_STRUT_PARTIAL"),
754 &length, struts.GetAs<uchar**> (), XA_CARDINAL);
755 if (!status || length != 12)
760 static_cast<int> (deskGeom.x ()),
761 static_cast<int> (deskGeom.y () + struts [4]),
762 static_cast<int> (struts [0]),
763 static_cast<int> (struts [5] - struts [4])
765 if (available.intersects (left))
766 available.setX (left.width ());
770 static_cast<int> (deskGeom.x () + deskGeom.width () - struts [1]),
771 static_cast<int> (deskGeom.y () + struts [6]),
772 static_cast<int> (struts [1]),
773 static_cast<int> (struts [7] - struts [6])
775 if (available.intersects (right))
776 available.setWidth (right.x () - available.x ());
780 static_cast<int> (deskGeom.x () + struts [8]),
781 static_cast<int> (deskGeom.y ()),
782 static_cast<int> (struts [9] - struts [8]),
783 static_cast<int> (struts [2])
785 if (available.intersects (top))
786 available.setY (top.height ());
790 static_cast<int> (deskGeom.x () + struts [10]),
791 static_cast<int> (deskGeom.y () + deskGeom.height () - struts [3]),
792 static_cast<int> (struts [11] - struts [10]),
793 static_cast<int> (struts [3])
795 if (available.intersects (bottom))
796 available.setHeight (bottom.y () - available.y ());
802 QRect XWrapper::GetAvailableGeometry (QWidget *widget)
804 return GetAvailableGeometry (QApplication::desktop ()->screenNumber (widget));
807 Atom XWrapper::GetAtom (
const QString& name)
809 if (Atoms_.contains (name))
810 return Atoms_ [name];
812 auto atom = XInternAtom (
Display_, name.toLocal8Bit (),
false);
813 Atoms_ [name] = atom;
817 bool XWrapper::GetWinProp (
Window win, Atom property,
818 ulong *length,
unsigned char **result, Atom req)
const
821 ulong type = 0, rest = 0;
822 return XGetWindowProperty (
Display_, win,
823 property, 0, 1024,
false, req, &type,
824 &fmt, length, &rest, result) == Success;
827 bool XWrapper::GetRootWinProp (Atom property,
828 ulong *length, uchar **result, Atom req)
const
830 return GetWinProp (AppWin_, property, length, result, req);
838 ulong *data =
nullptr;
840 if (!GetWinProp (wid, GetAtom (
"_NET_WM_WINDOW_TYPE"),
841 &length, reinterpret_cast<uchar**> (&data)))
844 for (ulong i = 0; i < length; ++i)
851 bool XWrapper::SendMessage (
Window wid, Atom atom, ulong d0, ulong d1, ulong d2, ulong d3, ulong d4)
853 XClientMessageEvent msg;
855 msg.type = ClientMessage;
856 msg.message_type = atom;
857 msg.send_event =
true;
866 return XSendEvent (
Display_, AppWin_,
false, SubstructureRedirectMask | SubstructureNotifyMask,
867 reinterpret_cast<XEvent*> (&msg)) == Success;
870 void XWrapper::initialize ()
static XWrapper & Instance()
detail::ExprTree< detail::ExprType::LeafStaticPlaceholder, boost::mpl::int_< Idx >> pos
Container< T > Filter(const Container< T > &c, F f)