23 #error "The HAVE_LIBDBUS symbol is not defined, you do not have lib dbus available, you should not be trying to compile dbus_notification.cpp"
26 #include <dbus/dbus.h>
28 #include <boost/cstdint.hpp>
29 #include <boost/multi_index_container.hpp>
30 #include <boost/multi_index/hashed_index.hpp>
31 #include <boost/multi_index/member.hpp>
35 #pragma GCC diagnostic ignored "-Wold-style-cast"
40 #define ERR_DU LOG_STREAM(err, log_desktop)
41 #define LOG_DU LOG_STREAM(info, log_desktop)
42 #define DBG_DU LOG_STREAM(info, log_desktop)
47 bool kde_style =
false;
66 using boost::multi_index::hashed_unique;
67 using boost::multi_index::indexed_by;
68 using boost::multi_index::tag;
69 using boost::multi_index::member;
71 typedef boost::multi_index_container<
75 hashed_unique<tag<by_id>, member<wnotify,const uint32_t,&wnotify::id> >,
77 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 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_connection()
105 static bool initted =
false;
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 <<
'\n';
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) {}
135 DBusMessage *buf = dbus_message_new_method_call(
136 kde_style ?
"org.kde.VisualNotifications" :
"org.freedesktop.Notifications",
137 kde_style ?
"/VisualNotifications" :
"/org/freedesktop/Notifications",
138 kde_style ?
"org.kde.VisualNotifications" :
"org.freedesktop.Notifications",
140 const char *app_name =
"Battle for Wesnoth";
141 dbus_message_append_args(buf,
142 DBUS_TYPE_STRING, &app_name,
143 DBUS_TYPE_UINT32, &replaces_id,
146 const char *event_id =
"";
147 dbus_message_append_args(buf,
148 DBUS_TYPE_STRING, &event_id,
154 ERR_DU <<
"Error: Could not find notification icon.\n"
156 <<
"normalized path =\'" << app_icon_ <<
"\'\n";
158 DBG_DU <<
"app_icon_=\'" << app_icon_ <<
"\'\n";
161 const char *
app_icon = app_icon_.c_str();
162 const char *summary = owner.c_str();
163 const char *
body = message.c_str();
164 const char **
actions =
nullptr;
165 dbus_message_append_args(buf,
166 DBUS_TYPE_STRING, &app_icon,
167 DBUS_TYPE_STRING, &summary,
168 DBUS_TYPE_STRING, &body,
169 DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &actions, 0,
171 DBusMessageIter iter, hints;
172 dbus_message_iter_init_append(buf, &iter);
173 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
"{sv}", &hints);
174 dbus_message_iter_close_container(&iter, &hints);
175 int expire_timeout = kde_style ? 5000 : -1;
176 dbus_message_append_args(buf,
177 DBUS_TYPE_INT32, &expire_timeout,
180 dbus_error_init(&err);
181 DBusMessage *ret = dbus_connection_send_with_reply_and_block(connection, buf, 1000, &err);
182 dbus_message_unref(buf);
184 ERR_DU <<
"Failed to send visual notification: " << err.message <<
'\n';
185 dbus_error_free(&err);
187 ERR_DU <<
" Retrying with the freedesktop protocol." << std::endl;
189 return send_dbus_notification(connection, replaces_id, owner, message);
194 dbus_message_get_args(ret,
nullptr,
195 DBUS_TYPE_UINT32, &
id,
197 dbus_message_unref(ret);
199 if (kde_style)
return 0;
211 DBusConnection *
connection = get_dbus_connection();
212 if (!connection)
return;
214 wnotify_by_owner & noticias = notifications.get<by_owner>();
216 wnotify_owner_it
i = noticias.find(owner);
218 if (i != noticias.end()) {
220 i->message = message +
"\n" + i->message;
222 size_t endl_pos = i->message.find(
'\n');
225 while (ctr < MAX_MSG_LINES && endl_pos != std::string::npos) {
226 endl_pos = i->message.find(
'\n', endl_pos+1);
230 i->message = i->message.substr(0,endl_pos);
235 send_dbus_notification(connection, i->id, owner, i->message);
238 uint32_t id = send_dbus_notification(connection, 0, owner, message);
240 wnotify visual(
id,owner,message);
241 std::pair<wnotify_owner_it, bool>
result = noticias.insert(visual);
242 if (!result.second) {
243 ERR_DU <<
"Failed to insert a dbus notification message:\n"
244 <<
"New Item:\n" <<
"\tid=" <<
id <<
"\n\towner=" << owner <<
"\n\tmessage=" << message <<
"\n"
245 <<
"Old Item:\n" <<
"\tid=" << result.first->id <<
"\n\towner=" << result.first->owner <<
"\n\tmessage=" << result.first->message <<
"\n";
const size_t MAX_MSG_LINES
static void body(LexState *ls, expdesc *e, int ismethod, int line)
void send_notification(const std::string &owner, const std::string &message, bool with_history)
std::string normalize_path(const std::string &path)
Returns the absolute path of a file.
void erase(const std::string &key)
GLenum GLuint GLsizei const char * buf
Declarations for File-IO.
static lg::log_domain log_desktop("desktop")
Standard logging facilities (interface).
GLsizei GLenum GLuint GLuint GLsizei char * message
bool file_exists(const std::string &name)
Returns true if a file or directory with such name already exists.
GLsizei const GLcharARB ** string