23 #error "The HAVE_LIBDBUS symbol is not defined, you do not have lib dbus available, you should not be trying to compile dbus_features.cpp"
26 #include <dbus/dbus.h>
28 #include <boost/multi_index_container.hpp>
29 #include <boost/multi_index/hashed_index.hpp>
30 #include <boost/multi_index/member.hpp>
36 #pragma GCC diagnostic ignored "-Wold-style-cast"
39 #define ERR_DU LOG_STREAM(err, log_desktop)
40 #define LOG_DU LOG_STREAM(info, log_desktop)
41 #define DBG_DU LOG_STREAM(info, log_desktop)
46 bool kde_style =
false;
50 wnotify(uint32_t id_arg,
const std::string & owner_arg,
const std::string & message_arg)
53 , message(message_arg)
59 mutable std::string message;
65 using boost::multi_index::hashed_unique;
66 using boost::multi_index::indexed_by;
67 using boost::multi_index::tag;
68 using boost::multi_index::member;
70 typedef boost::multi_index_container<
74 hashed_unique<tag<by_id>, member<wnotify,const uint32_t,&wnotify::id>>,
76 hashed_unique<tag<by_owner>, member<wnotify,const std::string,&wnotify::owner>>
84 wnotify_set notifications;
86 DBusHandlerResult filter_dbus_signal(DBusConnection *, DBusMessage *buf,
void *)
88 if (!dbus_message_is_signal(buf,
"org.freedesktop.Notifications",
"NotificationClosed")) {
89 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
93 dbus_message_get_args(buf,
nullptr,
94 DBUS_TYPE_UINT32, &
id,
97 std::size_t num_erased = notifications.get<by_id>().
erase(
id);
98 LOG_DU <<
"Erased " << num_erased <<
" notifications records matching id=" <<
id;
100 return DBUS_HANDLER_RESULT_HANDLED;
103 DBusConnection *get_dbus_session_bus()
105 static bool initted =
false;
106 static DBusConnection *connection =
nullptr;
111 if (getenv(
"KDE_SESSION_VERSION")) {
116 dbus_error_init(&
err);
117 connection = dbus_bus_get(DBUS_BUS_SESSION, &
err);
119 ERR_DU <<
"Failed to open DBus session: " <<
err.message;
120 dbus_error_free(&
err);
123 dbus_connection_add_filter(connection, filter_dbus_signal,
nullptr,
nullptr);
126 dbus_connection_read_write(connection, 0);
127 while (dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS) {}
132 DBusConnection *get_dbus_system_bus()
134 static DBusConnection *connection =
nullptr;
136 if (connection ==
nullptr)
139 dbus_error_init(&
err);
140 connection = dbus_bus_get(DBUS_BUS_SYSTEM, &
err);
141 dbus_error_free(&
err);
147 uint32_t send_dbus_notification(DBusConnection *connection, uint32_t replaces_id,
148 const std::string &owner,
const std::string &message)
150 DBusMessage *buf = dbus_message_new_method_call(
151 kde_style ?
"org.kde.VisualNotifications" :
"org.freedesktop.Notifications",
152 kde_style ?
"/VisualNotifications" :
"/org/freedesktop/Notifications",
153 kde_style ?
"org.kde.VisualNotifications" :
"org.freedesktop.Notifications",
155 const char *app_name =
"Battle for Wesnoth";
156 dbus_message_append_args(buf,
157 DBUS_TYPE_STRING, &app_name,
158 DBUS_TYPE_UINT32, &replaces_id,
161 const char *event_id =
"";
162 dbus_message_append_args(buf,
163 DBUS_TYPE_STRING, &event_id,
169 ERR_DU <<
"Error: Could not find notification icon.";
171 ERR_DU <<
"normalized path =\'" << app_icon_ <<
"\'";
173 DBG_DU <<
"app_icon_=\'" << app_icon_ <<
"\'";
176 const char *
app_icon = app_icon_.c_str();
177 const char *summary = owner.c_str();
178 const char *body = message.c_str();
179 const char **
actions =
nullptr;
180 dbus_message_append_args(buf,
182 DBUS_TYPE_STRING, &summary,
183 DBUS_TYPE_STRING, &body,
184 DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &
actions, 0,
186 DBusMessageIter iter, hints;
187 dbus_message_iter_init_append(buf, &iter);
188 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
"{sv}", &hints);
189 dbus_message_iter_close_container(&iter, &hints);
190 int expire_timeout = kde_style ? 5000 : -1;
191 dbus_message_append_args(buf,
192 DBUS_TYPE_INT32, &expire_timeout,
195 dbus_error_init(&
err);
196 DBusMessage *ret = dbus_connection_send_with_reply_and_block(connection, buf, 1000, &
err);
197 dbus_message_unref(buf);
199 ERR_DU <<
"Failed to send visual notification: " <<
err.message;
200 dbus_error_free(&
err);
202 ERR_DU <<
" Retrying with the freedesktop protocol.";
204 return send_dbus_notification(connection, replaces_id, owner, message);
209 dbus_message_get_args(ret,
nullptr,
210 DBUS_TYPE_UINT32, &
id,
212 dbus_message_unref(ret);
214 if (kde_style)
return 0;
219 T get_power_source_property(
const std::string &name, T fallback)
221 DBusConnection *connection = get_dbus_system_bus();
222 if (!connection)
return fallback;
224 std::unique_ptr<DBusMessage, std::function<void(DBusMessage*)>>
msg(dbus_message_new_method_call(
225 "org.freedesktop.UPower",
226 "/org/freedesktop/UPower/devices/DisplayDevice",
227 "org.freedesktop.DBus.Properties",
231 const char *interface_name =
"org.freedesktop.UPower.Device";
232 const char *property_name = name.data();
233 dbus_message_append_args(
msg.get(),
234 DBUS_TYPE_STRING, &interface_name,
235 DBUS_TYPE_STRING, &property_name,
239 dbus_error_init(&
err);
241 std::unique_ptr<DBusMessage, std::function<void(DBusMessage*)>> ret(dbus_connection_send_with_reply_and_block(
242 connection,
msg.get(), 1000, &
err), dbus_message_unref);
243 if (ret ==
nullptr) {
244 DBG_DU <<
"Failed to query power source properties: " <<
err.message;
245 dbus_error_free(&
err);
250 DBusMessageIter iter;
251 dbus_message_iter_init(ret.get(), &iter);
252 DBusMessageIter sub_iter;
253 dbus_message_iter_recurse(&iter, &sub_iter);
255 dbus_message_iter_get_basic(&sub_iter, &value);
266 void send_notification(
const std::string & owner,
const std::string & message,
bool with_history)
268 DBusConnection *connection = get_dbus_session_bus();
269 if (!connection)
return;
271 wnotify_by_owner & noticias = notifications.get<by_owner>();
273 wnotify_owner_it
i = noticias.find(owner);
275 if (
i != noticias.end()) {
277 i->message = message +
"\n" +
i->message;
279 std::size_t endl_pos =
i->message.find(
'\n');
282 while (ctr <
MAX_MSG_LINES && endl_pos != std::string::npos) {
283 endl_pos =
i->message.find(
'\n', endl_pos+1);
287 i->message =
i->message.substr(0,endl_pos);
289 i->message = message;
292 send_dbus_notification(connection,
i->id, owner,
i->message);
295 uint32_t
id = send_dbus_notification(connection, 0, owner, message);
297 wnotify visual(
id,owner,message);
298 std::pair<wnotify_owner_it, bool> result = noticias.insert(visual);
299 if (!result.second) {
300 ERR_DU <<
"Failed to insert a dbus notification message:";
301 ERR_DU <<
"New Item:\n" <<
"\tid=" <<
id <<
"\n\towner=" << owner <<
"\n\tmessage=" << message;
302 ERR_DU <<
"Old Item:\n" <<
"\tid=" << result.first->id <<
"\n\towner=" << result.first->owner <<
"\n\tmessage=" << result.first->message;
309 return get_power_source_property<uint32_t>(
"Type", 0) == 2;
314 return get_power_source_property<double>(
"Percentage", 0.0);
static lg::log_domain log_desktop("desktop")
Declarations for File-IO.
std::string id
Text to match against addon_info.tags()
Standard logging facilities (interface).
void send_notification(const std::string &owner, const std::string &message, bool with_history)
double get_battery_percentage()
const std::size_t MAX_MSG_LINES
bool does_device_have_battery()
static bool file_exists(const bfs::path &fpath)
std::string normalize_path(const std::string &fpath, bool normalize_separators, bool resolve_dot_entries)
Returns the absolute path of a file.
std::string & erase(std::string &str, const std::size_t start, const std::size_t len)
Erases a portion of a UTF-8 string.
std::string::const_iterator iterator
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")