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 SendMessage (wid, GetAtom (
"_NET_WM_DESKTOP"), num);
724 QRect XWrapper::GetAvailableGeometry (
int screen)
726 auto dw = QApplication::desktop ();
728 if (screen < 0 || screen >= dw->screenCount ())
729 screen = dw->primaryScreen ();
731 if (dw->isVirtualDesktop ())
734 auto available = dw->screenGeometry (screen);
735 const auto deskGeom = dw->rect ();
737 for (
const auto wid : GetWindows ())
740 Guarded<ulong> struts;
741 const auto status = GetWinProp (wid, GetAtom (
"_NET_WM_STRUT_PARTIAL"),
742 &length, struts.GetAs<uchar**> (), XA_CARDINAL);
743 if (!status || length != 12)
748 static_cast<int> (deskGeom.x ()),
749 static_cast<int> (deskGeom.y () + struts [4]),
750 static_cast<int> (struts [0]),
751 static_cast<int> (struts [5] - struts [4])
753 if (available.intersects (left))
754 available.setX (left.width ());
758 static_cast<int> (deskGeom.x () + deskGeom.width () - struts [1]),
759 static_cast<int> (deskGeom.y () + struts [6]),
760 static_cast<int> (struts [1]),
761 static_cast<int> (struts [7] - struts [6])
763 if (available.intersects (right))
764 available.setWidth (right.x () - available.x ());
768 static_cast<int> (deskGeom.x () + struts [8]),
769 static_cast<int> (deskGeom.y ()),
770 static_cast<int> (struts [9] - struts [8]),
771 static_cast<int> (struts [2])
773 if (available.intersects (top))
774 available.setY (top.height ());
778 static_cast<int> (deskGeom.x () + struts [10]),
779 static_cast<int> (deskGeom.y () + deskGeom.height () - struts [3]),
780 static_cast<int> (struts [11] - struts [10]),
781 static_cast<int> (struts [3])
783 if (available.intersects (bottom))
784 available.setHeight (bottom.y () - available.y ());
790 QRect XWrapper::GetAvailableGeometry (QWidget *widget)
792 return GetAvailableGeometry (QApplication::desktop ()->screenNumber (widget));
795 Atom XWrapper::GetAtom (
const QString& name)
797 if (Atoms_.contains (name))
798 return Atoms_ [name];
800 auto atom = XInternAtom (
Display_, name.toLocal8Bit (),
false);
801 Atoms_ [name] = atom;
805 bool XWrapper::GetWinProp (
Window win, Atom property,
806 ulong *length,
unsigned char **result, Atom req)
const
809 ulong type = 0, rest = 0;
810 return XGetWindowProperty (
Display_, win,
811 property, 0, 1024,
false, req, &type,
812 &fmt, length, &rest, result) == Success;
815 bool XWrapper::GetRootWinProp (Atom property,
816 ulong *length, uchar **result, Atom req)
const
818 return GetWinProp (AppWin_, property, length, result, req);
826 ulong *data =
nullptr;
828 if (!GetWinProp (wid, GetAtom (
"_NET_WM_WINDOW_TYPE"),
829 &length, reinterpret_cast<uchar**> (&data)))
832 for (ulong i = 0; i < length; ++i)
839 bool XWrapper::SendMessage (
Window wid, Atom atom, ulong d0, ulong d1, ulong d2, ulong d3, ulong d4)
841 XClientMessageEvent msg;
843 msg.type = ClientMessage;
844 msg.message_type = atom;
845 msg.send_event =
true;
854 return XSendEvent (
Display_, AppWin_,
false, SubstructureRedirectMask | SubstructureNotifyMask,
855 reinterpret_cast<XEvent*> (&msg)) == Success;
858 void XWrapper::initialize ()
static XWrapper & Instance()
auto Filter(const Container< T > &c, F f) -> Container< T >