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)
70 : Display_ (QX11Info::display ())
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 81 XSelectInput (Display_,
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);
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 200 XSync (Display_, False);
206 Guarded<Window> data;
209 if (GetRootWinProp (
GetAtom (
"_NET_CLIENT_LIST"), &length, data.GetAs<uchar**> ()))
210 for (ulong i = 0; i < length; ++i)
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));
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));
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))
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"));
422 XSelectInput (Display_, wid, PropertyChangeMask);
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" 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);
517 SendMessage (wid,
GetAtom (
"WM_CHANGE_STATE"), IconicState);
522 SendMessage (wid,
GetAtom (
"_NET_WM_STATE"), StateAdd,
523 GetAtom (
"_NET_WM_STATE_MAXIMIZED_VERT"),
524 GetAtom (
"_NET_WM_STATE_MAXIMIZED_HORZ"),
530 SendMessage (wid,
GetAtom (
"_NET_WM_STATE"), StateRemove,
531 GetAtom (
"_NET_WM_STATE_MAXIMIZED_VERT"),
532 GetAtom (
"_NET_WM_STATE_MAXIMIZED_HORZ"),
538 XResizeWindow (Display_, wid, width, height);
543 SendMessage (wid,
GetAtom (
"_NET_WM_STATE"),
544 StateAdd,
GetAtom (
"_NET_WM_STATE_SHADED"), 0, SourcePager);
549 SendMessage (wid,
GetAtom (
"_NET_WM_STATE"),
550 StateRemove,
GetAtom (
"_NET_WM_STATE_SHADED"), 0, SourcePager);
558 SendMessage (wid,
GetAtom (
"_NET_WM_STATE"), top,
559 GetAtom (
"_NET_WM_STATE_ABOVE"), 0, SourcePager);
561 SendMessage (wid,
GetAtom (
"_NET_WM_STATE"), bottom,
562 GetAtom (
"_NET_WM_STATE_BELOW"), 0, SourcePager);
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"))
583 else if (ev->atom ==
GetAtom (
"_NET_ACTIVE_WINDOW"))
585 else if (ev->atom ==
GetAtom (
"_NET_CURRENT_DESKTOP"))
590 if (ev->atom ==
GetAtom (
"_NET_WM_VISIBLE_NAME") ||
591 ev->atom ==
GetAtom (
"WM_NAME"))
593 else if (ev->atom ==
GetAtom (
"_NET_WM_ICON"))
595 else if (ev->atom ==
GetAtom (
"_NET_WM_DESKTOP"))
597 else if (ev->atom ==
GetAtom (
"_NET_WM_STATE"))
599 else if (ev->atom ==
GetAtom (
"_NET_WM_ALLOWED_ACTIONS"))
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"))
616 else if (ev->atom ==
GetAtom (
"_NET_ACTIVE_WINDOW"))
618 else if (ev->atom ==
GetAtom (
"_NET_CURRENT_DESKTOP"))
623 if (ev->atom ==
GetAtom (
"_NET_WM_VISIBLE_NAME") ||
624 ev->atom ==
GetAtom (
"WM_NAME"))
626 else if (ev->atom ==
GetAtom (
"_NET_WM_ICON"))
628 else if (ev->atom ==
GetAtom (
"_NET_WM_DESKTOP"))
630 else if (ev->atom ==
GetAtom (
"_NET_WM_STATE"))
632 else if (ev->atom ==
GetAtom (
"_NET_WM_ALLOWED_ACTIONS"))
638 Window XWrapper::GetActiveWindow ()
643 if (!GetRootWinProp (
GetAtom (
"_NET_ACTIVE_WINDOW"), &length, data.GetAs<uchar**> (), XA_WINDOW))
657 if (GetRootWinProp (
GetAtom (
"_NET_NUMBER_OF_DESKTOPS"), &length, data.GetAs<uchar**> (), XA_CARDINAL))
658 return length > 0 ? data [0] : -1;
668 if (GetRootWinProp (
GetAtom (
"_NET_CURRENT_DESKTOP"), &length, data.GetAs<uchar**> (), XA_CARDINAL))
669 return length > 0 ? data [0] : -1;
676 SendMessage (AppWin_,
GetAtom (
"_NET_CURRENT_DESKTOP"), desktop);
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;
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)
721 #if QT_VERSION < 0x050000 722 SendMessage (wid,
GetAtom (
"_NET_WM_DESKTOP"), num);
724 unsigned long data = num;
725 XChangeProperty (QX11Info::display (),
731 reinterpret_cast<unsigned char*> (&data),
738 auto dw = QApplication::desktop ();
740 if (screen < 0 || screen >= dw->screenCount ())
741 screen = dw->primaryScreen ();
743 if (dw->isVirtualDesktop ())
744 screen = DefaultScreen (Display_);
746 auto available = dw->screenGeometry (screen);
747 const auto deskGeom = dw->rect ();
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 ());
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;
858 msg.display = Display_;
866 return XSendEvent (Display_, AppWin_,
false, SubstructureRedirectMask | SubstructureNotifyMask,
867 reinterpret_cast<XEvent*> (&msg)) == Success;
870 void XWrapper::initialize ()
void windowDesktopChanged(ulong)
QRect GetAvailableGeometry(int screen=-1)
QIcon GetWindowIcon(Window)
void windowStateChanged(ulong)
static XWrapper & Instance()
void ClearStrut(QWidget *)
void MoveWindowToDesktop(Window, int)
int GetWindowDesktop(Window)
detail::ExprTree< detail::ExprType::LeafStaticPlaceholder, boost::mpl::int_< Idx >> pos
Window GetRootWindow() const
Atom GetAtom(const QString &)
void SetCurrentDesktop(int)
void UnshadeWindow(Window)
AllowedActionFlags GetWindowActions(Window)
void windowActionsChanged(ulong)
void ResizeWindow(Window, int, int)
void activeWindowChanged()
QList< Window > GetWindows()
void SetStrut(QWidget *, Qt::ToolBarArea)
void MoveWindowTo(Window, Layer)
QStringList GetDesktopNames()
void MaximizeWindow(Window)
WinStateFlags GetWindowState(Window)
void MinimizeWindow(Window)
QString GetDesktopName(int, const QString &=QString())
QString GetWindowTitle(Window)
void UnmaximizeWindow(Window)
Display * GetDisplay() const
void windowIconChanged(ulong)
void windowNameChanged(ulong)