LeechCraft  0.6.70-3565-g2d86529
Modular cross-platform feature rich live environment.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
xwrapper.cpp
Go to the documentation of this file.
1 /**********************************************************************
2  * LeechCraft - modular cross-platform feature rich internet client.
3  * Copyright (C) 2006-2014 Georg Rudoy
4  *
5  * Boost Software License - Version 1.0 - August 17th, 2003
6  *
7  * Permission is hereby granted, free of charge, to any person or organization
8  * obtaining a copy of the software and accompanying documentation covered by
9  * this license (the "Software") to use, reproduce, display, distribute,
10  * execute, and transmit the Software, and to prepare derivative works of the
11  * Software, and to permit third-parties to whom the Software is furnished to
12  * do so, all subject to the following:
13  *
14  * The copyright notices in the Software and this entire statement, including
15  * the above license grant, this restriction and the following disclaimer,
16  * must be included in all copies of the Software, in whole or in part, and
17  * all derivative works of the Software, unless such copies or derivative
18  * works are solely in the form of machine-executable object code generated by
19  * a source language processor.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
24  * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
25  * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
26  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27  * DEALINGS IN THE SOFTWARE.
28  **********************************************************************/
29 
30 #include "xwrapper.h"
31 #include <limits>
32 #include <type_traits>
33 #include <QString>
34 #include <QPixmap>
35 #include <QIcon>
36 #include <QApplication>
37 #include <QWidget>
38 #include <QDesktopWidget>
39 #include <QAbstractEventDispatcher>
40 #include <QtDebug>
41 #include <QTimer>
42 #include <X11/Xlib.h>
43 #include <X11/Xutil.h>
44 #include <X11/Xatom.h>
45 
46 #if QT_VERSION >= 0x050000
47 #include <xcb/xcb.h>
48 #endif
49 
50 namespace LeechCraft
51 {
52 namespace Util
53 {
54  const int SourcePager = 2;
55 
56  const int StateRemove = 0;
57  const int StateAdd = 1;
58 
59  namespace
60  {
61 #if QT_VERSION < 0x050000
62  bool EvFilter (void *msg)
63  {
64  return XWrapper::Instance ().Filter (static_cast<XEvent*> (msg));
65  }
66 #endif
67  }
68 
69  XWrapper::XWrapper ()
70  : Display_ (QX11Info::display ())
71  , AppWin_ (QX11Info::appRootWindow ())
72 #if QT_VERSION < 0x050000
73  , PrevFilter_ (QAbstractEventDispatcher::instance ()->setEventFilter (EvFilter))
74 #endif
75  {
76 #if QT_VERSION >= 0x050000
77  QAbstractEventDispatcher::instance ()->installNativeEventFilter (this);
78 #endif
79 
80 #if QT_VERSION < 0x050000
81  XSelectInput (Display_,
82  AppWin_,
83  PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask);
84 #else
85  const uint32_t rootEvents [] =
86  {
87  XCB_EVENT_MASK_STRUCTURE_NOTIFY |
88  XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
89  XCB_EVENT_MASK_PROPERTY_CHANGE
90  };
91  xcb_change_window_attributes (QX11Info::connection (),
92  AppWin_, XCB_CW_EVENT_MASK, rootEvents);
93 #endif
94  }
95 
96  XWrapper& XWrapper::Instance ()
97  {
98  static XWrapper w;
99  return w;
100  }
101 
102  Display* XWrapper::GetDisplay () const
103  {
104  return Display_;
105  }
106 
107  Window XWrapper::GetRootWindow () const
108  {
109  return AppWin_;
110  }
111 
112 #if QT_VERSION < 0x050000
114  {
115  if (ev->type == PropertyNotify)
116  HandlePropNotify (&ev->xproperty);
117 
118  return PrevFilter_ ? PrevFilter_ (ev) : false;
119  }
120 #else
121  bool XWrapper::nativeEventFilter (const QByteArray& eventType, void *msg, long int*)
122  {
123  if (eventType != "xcb_generic_event_t")
124  return false;
125 
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));
129 
130  return false;
131  }
132 #endif
133 
134  namespace
135  {
136  template<typename T>
137  struct IsDoublePtr : std::false_type {};
138 
139  template<typename T>
140  struct IsDoublePtr<T**> : std::true_type {};
141 
142  template<typename T>
143  class Guarded
144  {
145  T *Data_;
146  public:
147  Guarded ()
148  : Data_ { nullptr }
149  {
150  }
151 
152  ~Guarded ()
153  {
154  if (Data_)
155  XFree (Data_);
156  }
157 
158  T** Get (bool clear = true)
159  {
160  if (clear && Data_)
161  XFree (Data_);
162  return &Data_;
163  }
164 
165  template<typename U>
166  U GetAs (bool clear = true)
167  {
168  if (clear && Data_)
169  XFree (Data_);
170  return IsDoublePtr<U>::value ?
171  reinterpret_cast<U> (&Data_) :
172  reinterpret_cast<U> (Data_);
173  }
174 
175  T operator[] (size_t idx) const
176  {
177  return Data_ [idx];
178  }
179 
180  T& operator[] (size_t idx)
181  {
182  return Data_ [idx];
183  }
184 
185  operator bool () const
186  {
187  return Data_ != nullptr;
188  }
189 
190  bool operator! () const
191  {
192  return !Data_;
193  }
194  };
195  }
196 
197  void XWrapper::Sync ()
198  {
199  XFlush (Display_);
200  XSync (Display_, False);
201  }
202 
203  QList<Window> XWrapper::GetWindows ()
204  {
205  ulong length = 0;
206  Guarded<Window> data;
207 
208  QList<Window> result;
209  if (GetRootWinProp (GetAtom ("_NET_CLIENT_LIST"), &length, data.GetAs<uchar**> ()))
210  for (ulong i = 0; i < length; ++i)
211  result << data [i];
212  return result;
213  }
214 
215  QString XWrapper::GetWindowTitle (Window wid)
216  {
217  QString name;
218 
219  ulong length = 0;
220  Guarded<uchar> data;
221 
222  auto utf8Str = GetAtom ("UTF8_STRING");
223 
224  if (GetWinProp (wid, GetAtom ("_NET_WM_VISIBLE_NAME"), &length, data.Get (), utf8Str))
225  name = QString::fromUtf8 (data.GetAs<char*> (false));
226 
227  if (name.isEmpty ())
228  if (GetWinProp (wid, GetAtom ("_NET_WM_NAME"), &length, data.Get (), utf8Str))
229  name = QString::fromUtf8 (data.GetAs<char*> (false));
230 
231  if (name.isEmpty ())
232  if (GetWinProp (wid, GetAtom ("XA_WM_NAME"), &length, data.Get (), XA_STRING))
233  name = QString::fromUtf8 (data.GetAs<char*> (false));
234 
235  if (name.isEmpty ())
236  {
237  XFetchName (Display_, wid, data.GetAs<char**> ());
238  name = QString (data.GetAs<char*> (false));
239  }
240 
241  if (name.isEmpty ())
242  {
243  XTextProperty prop;
244  if (XGetWMName (Display_, wid, &prop))
245  {
246  name = QString::fromUtf8 (reinterpret_cast<char*> (prop.value));
247  XFree (prop.value);
248  }
249  }
250 
251  return name;
252  }
253 
254  QIcon XWrapper::GetWindowIcon (Window wid)
255  {
256  int fmt = 0;
257  ulong type, count, extra;
258  Guarded<ulong> data;
259 
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**> ());
264 
265  if (!data)
266  return {};
267 
268  QIcon icon;
269 
270  auto cur = *data.Get (false);
271  auto end = cur + count;
272  while (cur < end)
273  {
274  QImage img (cur [0], cur [1], QImage::Format_ARGB32);
275  cur += 2;
276  for (int i = 0; i < img.byteCount () / 4; ++i, ++cur)
277  reinterpret_cast<uint*> (img.bits ()) [i] = *cur;
278 
279  icon.addPixmap (QPixmap::fromImage (img));
280  }
281 
282  return icon;
283  }
284 
285  WinStateFlags XWrapper::GetWindowState (Window wid)
286  {
287  WinStateFlags result;
288 
289  ulong length = 0;
290  ulong *data = 0;
291  if (!GetWinProp (wid, GetAtom ("_NET_WM_STATE"),
292  &length, reinterpret_cast<uchar**> (&data), XA_ATOM))
293  return result;
294 
295  for (ulong i = 0; i < length; ++i)
296  {
297  const auto curAtom = data [i];
298 
299  auto set = [this, &curAtom, &result] (const QString& atom, WinStateFlag flag)
300  {
301  if (curAtom == GetAtom ("_NET_WM_STATE_" + atom))
302  result |= flag;
303  };
304 
305  set ("MODAL", WinStateFlag::Modal);
306  set ("STICKY", WinStateFlag::Sticky);
307  set ("MAXIMIZED_VERT", WinStateFlag::MaximizedVert);
308  set ("MAXIMIZED_HORZ", WinStateFlag::MaximizedHorz);
309  set ("SHADED", WinStateFlag::Shaded);
310  set ("SKIP_TASKBAR", WinStateFlag::SkipTaskbar);
311  set ("SKIP_PAGER", WinStateFlag::SkipPager);
312  set ("HIDDEN", WinStateFlag::Hidden);
313  set ("FULLSCREEN", WinStateFlag::Fullscreen);
314  set ("ABOVE", WinStateFlag::OnTop);
315  set ("BELOW", WinStateFlag::OnBottom);
316  set ("DEMANDS_ATTENTION", WinStateFlag::Attention);
317  }
318 
319  XFree (data);
320 
321  return result;
322  }
323 
324  AllowedActionFlags XWrapper::GetWindowActions (Window wid)
325  {
326  AllowedActionFlags result;
327 
328  ulong length = 0;
329  ulong *data = 0;
330  if (!GetWinProp (wid, GetAtom ("_NET_WM_ALLOWED_ACTIONS"),
331  &length, reinterpret_cast<uchar**> (&data), XA_ATOM))
332  return result;
333 
334  for (ulong i = 0; i < length; ++i)
335  {
336  const auto curAtom = data [i];
337 
338  auto set = [this, &curAtom, &result] (const QString& atom, AllowedActionFlag flag)
339  {
340  if (curAtom == GetAtom ("_NET_WM_ACTION_" + atom))
341  result |= flag;
342  };
343 
344  set ("MOVE", AllowedActionFlag::Move);
345  set ("RESIZE", AllowedActionFlag::Resize);
346  set ("MINIMIZE", AllowedActionFlag::Minimize);
347  set ("SHADE", AllowedActionFlag::Shade);
348  set ("STICK", AllowedActionFlag::Stick);
349  set ("MAXIMIZE_HORZ", AllowedActionFlag::MaximizeHorz);
350  set ("MAXIMIZE_VERT", AllowedActionFlag::MaximizeVert);
351  set ("FULLSCREEN", AllowedActionFlag::ShowFullscreen);
352  set ("CHANGE_DESKTOP", AllowedActionFlag::ChangeDesktop);
353  set ("CLOSE", AllowedActionFlag::Close);
354  set ("ABOVE", AllowedActionFlag::MoveToTop);
355  set ("BELOW", AllowedActionFlag::MoveToBottom);
356  }
357 
358  XFree (data);
359 
360  return result;
361  }
362 
363  Window XWrapper::GetActiveApp ()
364  {
365  auto win = GetActiveWindow ();
366  if (!win)
367  return 0;
368 
369  Window transient = None;
370  if (!ShouldShow (win) && XGetTransientForHint (Display_, win, &transient))
371  return transient;
372 
373  return win;
374  }
375 
376  bool XWrapper::IsLCWindow (Window wid)
377  {
378  ulong length = 0;
379  Guarded<uchar> data;
380  if (GetWinProp (wid, GetAtom ("WM_CLASS"), &length, data.Get ()) &&
381  QString (data.GetAs<char*> (false)).startsWith ("leechcraft"))
382  return true;
383 
384  return false;
385  }
386 
387  bool XWrapper::ShouldShow (Window wid)
388  {
389  const QList<Atom> ignoreAtoms
390  {
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")
398  };
399 
400  for (const auto& type : GetWindowType (wid))
401  if (ignoreAtoms.contains (type))
402  return false;
403 
404  if (GetWindowState (wid) & WinStateFlag::SkipTaskbar)
405  return false;
406 
407  Window transient = None;
408  if (!XGetTransientForHint (Display_, wid, &transient))
409  return true;
410 
411  if (transient == 0 || transient == wid || transient == AppWin_)
412  return true;
413 
414  return !GetWindowType (transient).contains (GetAtom ("_NET_WM_WINDOW_TYPE_NORMAL"));
415  }
416 
417  void XWrapper::Subscribe (Window wid)
418  {
419  if (IsLCWindow (wid))
420  return;
421 
422  XSelectInput (Display_, wid, PropertyChangeMask);
423  }
424 
425  void XWrapper::SetStrut (QWidget *widget, Qt::ToolBarArea area)
426  {
427  const auto wid = widget->effectiveWinId ();
428 
429  const auto& winGeom = widget->geometry ();
430 
431  switch (area)
432  {
433  case Qt::BottomToolBarArea:
434  SetStrut (wid,
435  0, 0, 0, winGeom.height (),
436  0, 0,
437  0, 0,
438  0, 0,
439  winGeom.left (), winGeom.right ());
440  break;
441  case Qt::TopToolBarArea:
442  SetStrut (wid,
443  0, 0, winGeom.height (), 0,
444  0, 0,
445  0, 0,
446  winGeom.left (), winGeom.right (),
447  0, 0);
448  break;
449  case Qt::LeftToolBarArea:
450  SetStrut (wid,
451  winGeom.width (), 0, 0, 0,
452  winGeom.top (), winGeom.bottom (),
453  0, 0,
454  0, 0,
455  0, 0);
456  break;
457  case Qt::RightToolBarArea:
458  SetStrut (wid,
459  0, winGeom.width (), 0, 0,
460  0, 0,
461  winGeom.top (), winGeom.bottom (),
462  0, 0,
463  0, 0);
464  break;
465  default:
466  qWarning () << Q_FUNC_INFO
467  << "incorrect area passed"
468  << area;
469  break;
470  }
471  }
472 
473  void XWrapper::ClearStrut (QWidget *w)
474  {
475  const auto wid = w->effectiveWinId ();
476  XDeleteProperty (Display_, wid, GetAtom ("_NET_WM_STRUT"));
477  XDeleteProperty (Display_, wid, GetAtom ("_NET_WM_STRUT_PARTIAL"));
478  }
479 
480  void XWrapper::SetStrut (Window wid,
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)
486  {
487  ulong struts[12] = { 0 };
488 
489  struts [0] = left;
490  struts [1] = right;
491  struts [2] = top;
492  struts [3] = bottom;
493 
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;
502 
503  XChangeProperty (Display_, wid, GetAtom ("_NET_WM_STRUT_PARTIAL"),
504  XA_CARDINAL, 32, PropModeReplace, reinterpret_cast<uchar*> (struts), 12);
505 
506  XChangeProperty (Display_, wid, GetAtom ("_NET_WM_STRUT"),
507  XA_CARDINAL, 32, PropModeReplace, reinterpret_cast<uchar*> (struts), 4);
508  }
509 
510  void XWrapper::RaiseWindow (Window wid)
511  {
512  SendMessage (wid, GetAtom ("_NET_ACTIVE_WINDOW"), SourcePager);
513  }
514 
515  void XWrapper::MinimizeWindow (Window wid)
516  {
517  SendMessage (wid, GetAtom ("WM_CHANGE_STATE"), IconicState);
518  }
519 
520  void XWrapper::MaximizeWindow (Window wid)
521  {
522  SendMessage (wid, GetAtom ("_NET_WM_STATE"), StateAdd,
523  GetAtom ("_NET_WM_STATE_MAXIMIZED_VERT"),
524  GetAtom ("_NET_WM_STATE_MAXIMIZED_HORZ"),
525  SourcePager);
526  }
527 
528  void XWrapper::UnmaximizeWindow (Window wid)
529  {
530  SendMessage (wid, GetAtom ("_NET_WM_STATE"), StateRemove,
531  GetAtom ("_NET_WM_STATE_MAXIMIZED_VERT"),
532  GetAtom ("_NET_WM_STATE_MAXIMIZED_HORZ"),
533  SourcePager);
534  }
535 
536  void XWrapper::ResizeWindow (Window wid, int width, int height)
537  {
538  XResizeWindow (Display_, wid, width, height);
539  }
540 
541  void XWrapper::ShadeWindow (Window wid)
542  {
543  SendMessage (wid, GetAtom ("_NET_WM_STATE"),
544  StateAdd, GetAtom ("_NET_WM_STATE_SHADED"), 0, SourcePager);
545  }
546 
547  void XWrapper::UnshadeWindow (Window wid)
548  {
549  SendMessage (wid, GetAtom ("_NET_WM_STATE"),
550  StateRemove, GetAtom ("_NET_WM_STATE_SHADED"), 0, SourcePager);
551  }
552 
553  void XWrapper::MoveWindowTo (Window wid, Layer layer)
554  {
555  const auto top = layer == Layer::Top ? StateAdd : StateRemove;
556  const auto bottom = layer == Layer::Bottom ? StateAdd : StateRemove;
557 
558  SendMessage (wid, GetAtom ("_NET_WM_STATE"), top,
559  GetAtom ("_NET_WM_STATE_ABOVE"), 0, SourcePager);
560 
561  SendMessage (wid, GetAtom ("_NET_WM_STATE"), bottom,
562  GetAtom ("_NET_WM_STATE_BELOW"), 0, SourcePager);
563  }
564 
565  void XWrapper::CloseWindow (Window wid)
566  {
567  SendMessage (wid, GetAtom ("_NET_CLOSE_WINDOW"), 0, SourcePager);
568  }
569 
570 #if QT_VERSION < 0x050000
571  template<typename T>
572  void XWrapper::HandlePropNotify (T ev)
573  {
574  if (ev->state == PropertyDelete)
575  return;
576 
577  const auto wid = ev->window;
578 
579  if (wid == AppWin_)
580  {
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 ();
587  }
588  else
589  {
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);
601  }
602  }
603 #else
604  template<typename T>
605  void XWrapper::HandlePropNotify (T ev)
606  {
607  if (ev->state == XCB_PROPERTY_DELETE)
608  return;
609 
610  const auto wid = ev->window;
611 
612  if (wid == AppWin_)
613  {
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 ();
620  }
621  else
622  {
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);
634  }
635  }
636 #endif
637 
638  Window XWrapper::GetActiveWindow ()
639  {
640  ulong length = 0;
641  Guarded<ulong> data;
642 
643  if (!GetRootWinProp (GetAtom ("_NET_ACTIVE_WINDOW"), &length, data.GetAs<uchar**> (), XA_WINDOW))
644  return 0;
645 
646  if (!length)
647  return 0;
648 
649  return data [0];
650  }
651 
652  int XWrapper::GetDesktopCount ()
653  {
654  ulong length = 0;
655  Guarded<ulong> data;
656 
657  if (GetRootWinProp (GetAtom ("_NET_NUMBER_OF_DESKTOPS"), &length, data.GetAs<uchar**> (), XA_CARDINAL))
658  return length > 0 ? data [0] : -1;
659 
660  return -1;
661  }
662 
663  int XWrapper::GetCurrentDesktop ()
664  {
665  ulong length = 0;
666  Guarded<ulong> data;
667 
668  if (GetRootWinProp (GetAtom ("_NET_CURRENT_DESKTOP"), &length, data.GetAs<uchar**> (), XA_CARDINAL))
669  return length > 0 ? data [0] : -1;
670 
671  return -1;
672  }
673 
674  void XWrapper::SetCurrentDesktop (int desktop)
675  {
676  SendMessage (AppWin_, GetAtom ("_NET_CURRENT_DESKTOP"), desktop);
677  }
678 
679  QStringList XWrapper::GetDesktopNames ()
680  {
681  ulong length = 0;
682  Guarded<uchar> data;
683 
684  if (!GetRootWinProp (GetAtom ("_NET_DESKTOP_NAMES"),
685  &length, data.GetAs<uchar**> (), GetAtom ("UTF8_STRING")))
686  return {};
687 
688  if (!data)
689  return {};
690 
691  QStringList result;
692  for (char *pos = data.GetAs<char*> (false), *end = data.GetAs<char*> (false) + length; pos < end; )
693  {
694  const auto& str = QString::fromUtf8 (pos);
695  result << str;
696  pos += str.toUtf8 ().size () + 1;
697  }
698  return result;
699  }
700 
701  QString XWrapper::GetDesktopName (int desktop, const QString& def)
702  {
703  return GetDesktopNames ().value (desktop, def);
704  }
705 
706  int XWrapper::GetWindowDesktop (Window wid)
707  {
708  ulong length = 0;
709  Guarded<ulong> data;
710  if (GetWinProp (wid, GetAtom ("_NET_WM_DESKTOP"), &length, data.GetAs<uchar**> (), XA_CARDINAL) && length)
711  return data [0];
712 
713  if (GetWinProp (wid, GetAtom ("_WIN_WORKSPACE"), &length, data.GetAs<uchar**> (), XA_CARDINAL) && length)
714  return data [0];
715 
716  return -1;
717  }
718 
719  void XWrapper::MoveWindowToDesktop (Window wid, int num)
720  {
721  SendMessage (wid, GetAtom ("_NET_WM_DESKTOP"), num);
722  }
723 
724  QRect XWrapper::GetAvailableGeometry (int screen)
725  {
726  auto dw = QApplication::desktop ();
727 
728  if (screen < 0 || screen >= dw->screenCount ())
729  screen = dw->primaryScreen ();
730 
731  if (dw->isVirtualDesktop ())
732  screen = DefaultScreen (Display_);
733 
734  auto available = dw->screenGeometry (screen);
735  const auto deskGeom = dw->rect ();
736 
737  for (const auto wid : GetWindows ())
738  {
739  ulong length = 0;
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)
744  continue;
745 
746  const QRect left
747  {
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])
752  };
753  if (available.intersects (left))
754  available.setX (left.width ());
755 
756  const QRect right
757  {
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])
762  };
763  if (available.intersects (right))
764  available.setWidth (right.x () - available.x ());
765 
766  const QRect top
767  {
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])
772  };
773  if (available.intersects (top))
774  available.setY (top.height ());
775 
776  const QRect bottom
777  {
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])
782  };
783  if (available.intersects (bottom))
784  available.setHeight (bottom.y () - available.y ());
785  }
786 
787  return available;
788  }
789 
790  QRect XWrapper::GetAvailableGeometry (QWidget *widget)
791  {
792  return GetAvailableGeometry (QApplication::desktop ()->screenNumber (widget));
793  }
794 
795  Atom XWrapper::GetAtom (const QString& name)
796  {
797  if (Atoms_.contains (name))
798  return Atoms_ [name];
799 
800  auto atom = XInternAtom (Display_, name.toLocal8Bit (), false);
801  Atoms_ [name] = atom;
802  return atom;
803  }
804 
805  bool XWrapper::GetWinProp (Window win, Atom property,
806  ulong *length, unsigned char **result, Atom req) const
807  {
808  int fmt = 0;
809  ulong type = 0, rest = 0;
810  return XGetWindowProperty (Display_, win,
811  property, 0, 1024, false, req, &type,
812  &fmt, length, &rest, result) == Success;
813  }
814 
815  bool XWrapper::GetRootWinProp (Atom property,
816  ulong *length, uchar **result, Atom req) const
817  {
818  return GetWinProp (AppWin_, property, length, result, req);
819  }
820 
821  QList<Atom> XWrapper::GetWindowType (Window wid)
822  {
823  QList<Atom> result;
824 
825  ulong length = 0;
826  ulong *data = nullptr;
827 
828  if (!GetWinProp (wid, GetAtom ("_NET_WM_WINDOW_TYPE"),
829  &length, reinterpret_cast<uchar**> (&data)))
830  return result;
831 
832  for (ulong i = 0; i < length; ++i)
833  result << data [i];
834 
835  XFree (data);
836  return result;
837  }
838 
839  bool XWrapper::SendMessage (Window wid, Atom atom, ulong d0, ulong d1, ulong d2, ulong d3, ulong d4)
840  {
841  XClientMessageEvent msg;
842  msg.window = wid;
843  msg.type = ClientMessage;
844  msg.message_type = atom;
845  msg.send_event = true;
846  msg.display = Display_;
847  msg.format = 32;
848  msg.data.l [0] = d0;
849  msg.data.l [1] = d1;
850  msg.data.l [2] = d2;
851  msg.data.l [3] = d3;
852  msg.data.l [4] = d4;
853 
854  return XSendEvent (Display_, AppWin_, false, SubstructureRedirectMask | SubstructureNotifyMask,
855  reinterpret_cast<XEvent*> (&msg)) == Success;
856  }
857 
858  void XWrapper::initialize ()
859  {
860  }
861 }
862 }
static XWrapper & Instance()
Definition: xwrapper.cpp:96
union _XEvent XEvent
Definition: xwrapper.h:55
const int StateRemove
Definition: xwrapper.cpp:56
const int StateAdd
Definition: xwrapper.cpp:57
T * Data_
Definition: xwrapper.cpp:145
auto Filter(const Container< T > &c, F f) -> Container< T >
Definition: prelude.h:169
QWidget * Display_
Definition: util.cpp:85
const int SourcePager
Definition: xwrapper.cpp:54
No type (item doesn't correspond to a radio station).
unsigned long Window
Definition: xwrapper.h:50