LeechCraft 0.6.70-16373-g319c272718
Modular cross-platform feature rich live environment.
Loading...
Searching...
No Matches
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
93namespace 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
136
138 {
139 emit Adaptor_.NewStatus ();
140 }
141}
142
143namespace 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}
const IconInfo & GetInfo() const
SNIAdaptor(FancyTrayIconFreedesktop &)
QList< IconFrame > IconToFrames(const QIcon &icon)
const QDBusArgument & operator>>(const QDBusArgument &in, IconFrame &frame)
QDBusArgument & operator<<(QDBusArgument &out, const IconFrame &frame)
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
static IconFrame FromPixmap(const QPixmap &)