LeechCraft  0.6.70-16373-g319c272718
Modular cross-platform feature rich live environment.
fancytrayiconfreedesktop.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  * Distributed under the Boost Software License, Version 1.0.
6  * (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt)
7  **********************************************************************/
8 
10 #include <QCoreApplication>
11 #include <QDBusArgument>
12 #include <QDBusInterface>
13 #include <QDBusConnection>
14 #include <QDBusConnectionInterface>
15 #include <QDBusMetaType>
16 #include <QMenu>
17 #include <QtDebug>
18 #include <QtEndian>
19 #include <util/sll/prelude.h>
20 #include <util/sll/qtutil.h>
21 #include <util/sll/visitor.h>
22 
24 {
25  IconFrame IconFrame::FromPixmap (const QPixmap& px)
26  {
27  const auto& img = px.toImage ().convertToFormat (QImage::Format_ARGB32);
28 
29  QByteArray data;
30  const auto pixelsCnt = img.width () * img.height ();
31  data.resize (pixelsCnt * sizeof (quint32));
32  qToBigEndian<quint32> (img.bits (), pixelsCnt, data.data ());
33 
34  return { .Width_ = img.width (), .Height_ = img.height (), .Data_ = data };
35  }
36 
37  QList<IconFrame> IconToFrames (const QIcon& icon)
38  {
39  if (icon.isNull ())
40  return {};
41 
42  auto sizes = icon.availableSizes ();
43  constexpr auto fallbackSize = 128;
44  if (sizes.isEmpty ())
45  sizes << QSize { fallbackSize, fallbackSize };
46 
47  return Util::Map (sizes, [&] (QSize size) { return IconFrame::FromPixmap (icon.pixmap (size)); });
48  }
49 
50  QDBusArgument& operator<< (QDBusArgument& out, const IconFrame& frame)
51  {
52  out.beginStructure ();
53  out << frame.Width_ << frame.Height_ << frame.Data_;
54  out.endStructure ();
55  return out;
56  }
57 
58  const QDBusArgument& operator>> (const QDBusArgument& in, IconFrame& frame)
59  {
60  in.beginStructure ();
61  in >> frame.Width_ >> frame.Height_ >> frame.Data_;
62  in.endStructure ();
63  return in;
64  }
65 
66  QDBusArgument& operator<< (QDBusArgument& out, const DBusTooltip& tooltip)
67  {
68  out.beginStructure ();
69  out << QString {};
70  out << IconToFrames (QIcon {});
71  out << tooltip.Title_;
72  out << tooltip.Subtitle_;
73  out.endStructure ();
74  return out;
75  }
76 
77  const QDBusArgument& operator>> (const QDBusArgument& in, DBusTooltip& tooltip)
78  {
79  QString iconName;
80  QList<IconFrame> frames;
81 
82  in.beginStructure ();
83  in >> iconName;
84  in >> frames;
85  in >> tooltip.Title_;
86  in >> tooltip.Subtitle_;
87  in.endStructure ();
88 
89  return in;
90  }
91 }
92 
93 namespace LC::Util
94 {
96  : FancyTrayIconImpl { &icon }
97  , FTI_ { icon }
98  , Adaptor_ { *this }
99  {
100  auto sb = QDBusConnection::sessionBus ();
101 
102  const auto& watchers = sb.interface ()->registeredServiceNames ().value ().filter ("StatusNotifierWatcher");
103  if (watchers.isEmpty ())
104  throw std::runtime_error { "no SNI watchers available" };
105  const auto& watcherService = watchers.value (0);
106  QDBusInterface watcher { watcherService, "/StatusNotifierWatcher", {}, sb };
107  if (!watcher.isValid ())
108  throw std::runtime_error { "interface to the SNI watcher " + watcherService.toStdString () + "is invalid" };
109 
110  static int uniqueId = 0;
111  const auto& serviceName = u"org.freedesktop.StatusNotifierItem-%1-%2"_qsv
112  .arg (QByteArray::number (QCoreApplication::applicationPid ()), QByteArray::number (++uniqueId));
113  if (!sb.registerService (serviceName))
114  throw std::runtime_error { "unable to register SNI service" };
115  if (!sb.registerObject ("/StatusNotifierItem", this))
116  throw std::runtime_error { "unable to register SNI object" };
117 
118  if (const auto reply = watcher.call ("RegisterStatusNotifierItem", serviceName);
119  reply.type () == QDBusMessage::ErrorMessage)
120  throw std::runtime_error { "unable to register the SNI with the watcher: " + reply.errorMessage ().toStdString () };
121  }
122 
124  {
125  emit Adaptor_.NewIcon ();
126  }
127 
129  {
130  emit Adaptor_.NewTooltip ();
131  }
132 
134  {
135  }
136 
138  {
139  emit Adaptor_.NewStatus ();
140  }
141 }
142 
143 namespace LC::Util::detail
144 {
146  : QDBusAbstractAdaptor { &impl }
147  , Impl_ { impl }
148  {
149  qDBusRegisterMetaType<IconFrame> ();
150  qDBusRegisterMetaType<QList<IconFrame>> ();
151  qDBusRegisterMetaType<DBusTooltip> ();
152  }
153 
154  void SNIAdaptor::ContextMenu (int x, int y)
155  {
156  if (const auto menu = Impl_.FTI_.GetContextMenu ())
157  menu->popup ({ x, y });
158  }
159 
160  void SNIAdaptor::Activate (int, int)
161  {
162  emit Impl_.FTI_.activated ();
163  }
164 
166  {
167  emit Impl_.FTI_.secondaryActivated ();
168  }
169 
170  void SNIAdaptor::Scroll (int delta, const QString& orient)
171  {
172  emit Impl_.FTI_.scrolled (delta, orient == u"Vertical"_qsv ? Qt::Vertical : Qt::Horizontal);
173  }
174 
175  QString SNIAdaptor::GetId () const
176  {
177  return Impl_.FTI_.GetInfo ().Id_;
178  }
179 
180  QString SNIAdaptor::GetTitle () const
181  {
182  return Impl_.FTI_.GetInfo ().Title_;
183  }
184 
185  QString SNIAdaptor::GetStatus () const
186  {
187  switch (Impl_.FTI_.GetStatus ())
188  {
190  return "Passive";
192  return "Active";
194  return "NeedsAttention";
195  }
196 
197  qWarning () << Q_FUNC_INFO
198  << "unknown status";
199  return "Active";
200  }
201 
202  QString SNIAdaptor::GetIconName () const
203  {
204  return Util::Visit (Impl_.FTI_.GetIcon (),
205  [] (const QString& path) { return path; },
206  [] (const QIcon&) { return QString {}; });
207  }
208 
209  QList<IconFrame> SNIAdaptor::GetIconPixmap () const
210  {
211  return Util::Visit (Impl_.FTI_.GetIcon (),
212  [] (const QString&) { return QList<IconFrame> {}; },
213  [] (const QIcon& icon) { return IconToFrames (icon); });
214  }
215 
216  DBusTooltip SNIAdaptor::GetTooltip () const
217  {
218  return
219  {
220  .Title_ = Impl_.FTI_.GetInfo ().Title_,
221  .Subtitle_ = Impl_.FTI_.GetTooltip ().HTML_
222  };
223  }
224 }
QMenu * GetContextMenu() const
const Icon & GetIcon() const
static IconFrame FromPixmap(const QPixmap &)
const Tooltip & GetTooltip() const
void scrolled(int, Qt::Orientation)
auto Visit(const Either< Left, Right > &either, Args &&... args)
Definition: either.h:215
auto Map(Container &&c, F &&f) noexcept(noexcept(std::is_nothrow_invocable_v< F, decltype(*c.begin())>))
Definition: prelude.h:104
SNIAdaptor(FancyTrayIconFreedesktop &)
const IconInfo & GetInfo() const
QDBusArgument & operator<<(QDBusArgument &out, const IconFrame &frame)
QList< IconFrame > IconToFrames(const QIcon &icon)
Status GetStatus() const
const QDBusArgument & operator>>(const QDBusArgument &in, IconFrame &frame)