Basic dbus functionality reintroduced

This commit is contained in:
Sascha Kruse 2013-02-18 04:30:57 +00:00
parent e6125914ab
commit 820cfe7315
5 changed files with 257 additions and 327 deletions

View File

@ -25,7 +25,7 @@ ifeq (${PKG_CONFIG}, ${EMPTY})
$(error "Failed to find pkg-config, please make sure it is installed) $(error "Failed to find pkg-config, please make sure it is installed)
endif endif
pkg_config_packs:="dbus-1 libxdg-basedir x11 freetype2 xext xft xscrnsaver glib-2.0" pkg_config_packs:="dbus-1 libxdg-basedir x11 freetype2 xext xft xscrnsaver glib-2.0 gio-2.0"
# includes and libs # includes and libs
INCS := $(shell ${PKG_CONFIG} --cflags ${pkg_config_packs}) INCS := $(shell ${PKG_CONFIG} --cflags ${pkg_config_packs})

View File

@ -1334,11 +1334,10 @@ bool is_idle(void)
return screensaver_info->idle / 1000 > idle_threshold; return screensaver_info->idle / 1000 > idle_threshold;
} }
static gboolean run(gpointer data) gboolean run(gpointer data)
{ {
printf("running\n"); printf("running\n");
time_t last_time = time(&last_time); time_t last_time = time(&last_time);
dbus_poll(1);
now = time(&now); now = time(&now);
time_t delta = now - last_time; time_t delta = now - last_time;
@ -1895,7 +1894,7 @@ int main(int argc, char *argv[])
usage(EXIT_SUCCESS); usage(EXIT_SUCCESS);
} }
initdbus(); int owner_id = initdbus();
setup(); setup();
signal (SIGUSR1, pause_signal_handler); signal (SIGUSR1, pause_signal_handler);
signal (SIGUSR2, pause_signal_handler); signal (SIGUSR2, pause_signal_handler);
@ -1943,6 +1942,8 @@ int main(int argc, char *argv[])
g_main_loop_run(mainloop); g_main_loop_run(mainloop);
g_bus_unown_name(owner_id);
return 0; return 0;
} }

View File

@ -36,6 +36,11 @@ typedef struct _screen_info {
dimension_t dim; dimension_t dim;
} screen_info; } screen_info;
typedef struct _actions {
char **actions;
int count;
} Actions;
typedef struct _notification { typedef struct _notification {
char *appname; char *appname;
char *summary; char *summary;
@ -58,6 +63,7 @@ typedef struct _notification {
int line_count; int line_count;
const char *script; const char *script;
char *urls; char *urls;
Actions *actions;
} notification; } notification;
typedef struct _rule_t { typedef struct _rule_t {
@ -97,5 +103,6 @@ int init_notification(notification * n, int id);
int close_notification(notification * n, int reason); int close_notification(notification * n, int reason);
int close_notification_by_id(int id, int reason); int close_notification_by_id(int id, int reason);
void map_win(void); void map_win(void);
gboolean run(void *data);
/* vim: set ts=8 sw=8 tw=0: */ /* vim: set ts=8 sw=8 tw=0: */

View File

@ -1,41 +1,13 @@
/* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */ /* copyright 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */
#include <glib.h> #include <glib.h>
#include <dbus/dbus.h> #include <gio/gio.h>
#include "dunst.h" #include "dunst.h"
#include "dunst_dbus.h" #include "dunst_dbus.h"
DBusError dbus_err; static GDBusNodeInfo *introspection_data = NULL;
DBusConnection *dbus_conn;
dbus_uint32_t dbus_serial = 0;
static void _extract_basic(int type, DBusMessageIter * iter, void *target) static const char *introspection_xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
{
int iter_type = dbus_message_iter_get_arg_type(iter);
if (iter_type == type) {
dbus_message_iter_get_basic(iter, target);
}
}
static void
_extract_hint(int type, const char *name, const char *hint_name,
DBusMessageIter * hint, void *target)
{
DBusMessageIter hint_value;
if (!strcmp(hint_name, name)) {
dbus_message_iter_next(hint);
dbus_message_iter_recurse(hint, &hint_value);
do {
_extract_basic(type, &hint_value, target);
} while (dbus_message_iter_next(hint));
}
}
static const char *introspect = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
"<node name=\"/org/freedesktop/Notifications\">" "<node name=\"/org/freedesktop/Notifications\">"
" <interface name=\"org.freedesktop.Notifications\">" " <interface name=\"org.freedesktop.Notifications\">"
" " " "
@ -76,313 +48,267 @@ static const char *introspect = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
" <interface name=\"org.xfce.Notifyd\">" " <interface name=\"org.xfce.Notifyd\">"
" <method name=\"Quit\"/>" " </interface>" "</node>"; " <method name=\"Quit\"/>" " </interface>" "</node>";
void dbus_introspect(DBusMessage * dmsg)
static void onGetCapabilities(GDBusConnection *connection,
const gchar *sender,
const GVariant *parameters,
GDBusMethodInvocation *invocation);
static void onNotify(GDBusConnection *connection,
const gchar *sender,
GVariant *parameters,
GDBusMethodInvocation *invocation);
static void onCloseNotification(GDBusConnection *connection,
const gchar *sender,
const GVariant *parameters,
GDBusMethodInvocation *invocation);
static void onGetServerInformation(GDBusConnection *connection,
const gchar *sender,
const GVariant *parameters,
GDBusMethodInvocation *invocation);
void handle_method_call(GDBusConnection *connection,
const gchar *sender,
const gchar *object_path,
const gchar *interface_name,
const gchar *method_name,
GVariant *parameters,
GDBusMethodInvocation *invocation,
gpointer user_data)
{ {
DBusMessage *reply; if (g_strcmp0(method_name, "GetCapabilities") == 0) {
DBusMessageIter args; onGetCapabilities(connection, sender, parameters, invocation);
reply = dbus_message_new_method_return(dmsg);
dbus_message_iter_init_append(reply, &args);
dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &introspect);
dbus_connection_send(dbus_conn, reply, &dbus_serial);
dbus_message_unref(reply);
}
void initdbus(void)
{
int ret;
dbus_error_init(&dbus_err);
dbus_conn = dbus_bus_get(DBUS_BUS_SESSION, &dbus_err);
if (dbus_error_is_set(&dbus_err)) {
fprintf(stderr, "Connection Error (%s)\n", dbus_err.message);
dbus_error_free(&dbus_err);
} }
if (dbus_conn == NULL) { else if (g_strcmp0(method_name, "Notify") == 0) {
fprintf(stderr, "dbus_con == NULL\n"); onNotify(connection, sender, parameters, invocation);
exit(EXIT_FAILURE);
} }
else if (g_strcmp0(method_name, "CloseNotification") == 0) {
ret = dbus_bus_request_name(dbus_conn, "org.freedesktop.Notifications", onCloseNotification(connection, sender, parameters, invocation);
DBUS_NAME_FLAG_REPLACE_EXISTING, &dbus_err);
if (dbus_error_is_set(&dbus_err)) {
fprintf(stderr, "Name Error (%s)\n", dbus_err.message);
} }
if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) { else if (g_strcmp0(method_name, "GetServerInformation") == 0) {
fprintf(stderr, onGetServerInformation(connection, sender, parameters, invocation);
"There's already another notification-daemon running\n");
exit(EXIT_FAILURE);
}
dbus_bus_add_match(dbus_conn,
"type='signal',interface='org.freedesktop.Notifications'",
&dbus_err);
if (dbus_error_is_set(&dbus_err)) {
fprintf(stderr, "Match error (%s)\n", dbus_err.message);
exit(EXIT_FAILURE);
}
}
void dbus_poll(int timeout)
{
DBusMessage *dbus_msg;
dbus_connection_read_write(dbus_conn, timeout);
dbus_msg = dbus_connection_pop_message(dbus_conn);
while (dbus_msg) {
if (dbus_message_is_method_call
(dbus_msg, "org.freedesktop.DBus.Introspectable", "Introspect")) {
dbus_introspect(dbus_msg);
}
if (dbus_message_is_method_call(dbus_msg,
"org.freedesktop.Notifications",
"Notify")) {
notify(dbus_msg);
}
if (dbus_message_is_method_call(dbus_msg,
"org.freedesktop.Notifications",
"GetCapabilities")) {
getCapabilities(dbus_msg);
}
if (dbus_message_is_method_call(dbus_msg,
"org.freedesktop.Notifications",
"GetServerInformation")) {
getServerInformation(dbus_msg);
}
if (dbus_message_is_method_call(dbus_msg,
"org.freedesktop.Notifications",
"CloseNotification")) {
closeNotification(dbus_msg);
}
dbus_message_unref(dbus_msg);
dbus_msg = dbus_connection_pop_message(dbus_conn);
}
}
void getCapabilities(DBusMessage * dmsg)
{
DBusMessage *reply;
DBusMessageIter args;
DBusMessageIter subargs;
const char *caps[1] = { "body" };
dbus_serial++;
reply = dbus_message_new_method_return(dmsg);
if (!reply) {
return;
}
dbus_message_iter_init_append(reply, &args);
if (!dbus_message_iter_open_container
(&args, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING, &subargs)
|| !dbus_message_iter_append_basic(&subargs, DBUS_TYPE_STRING, caps)
|| !dbus_message_iter_close_container(&args, &subargs)
|| !dbus_connection_send(dbus_conn, reply, &dbus_serial)) {
fprintf(stderr, "Unable to reply");
return;
}
dbus_connection_flush(dbus_conn);
dbus_message_unref(reply);
}
void closeNotification(DBusMessage * dmsg)
{
DBusMessage *reply;
DBusMessageIter args;
int id = 0;
reply = dbus_message_new_method_return(dmsg);
if (!reply) {
return;
}
dbus_message_iter_init(dmsg, &args);
_extract_basic(DBUS_TYPE_UINT32, &args, &id);
close_notification_by_id(id, 3);
dbus_connection_send(dbus_conn, reply, &dbus_serial);
dbus_connection_flush(dbus_conn);
}
void getServerInformation(DBusMessage * dmsg)
{
DBusMessage *reply;
DBusMessageIter args;
char *param = "";
const char *info[4] = { "dunst", "dunst", "2011", "2011" };
if (!dbus_message_iter_init(dmsg, &args)) {
} else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) {
} else { } else {
dbus_message_iter_get_basic(&args, &param); g_object_unref(invocation);
} }
reply = dbus_message_new_method_return(dmsg); printf("sender: %s\nmethod_name: %s\n", sender, method_name);
}
dbus_message_iter_init_append(reply, &args); static void onGetCapabilities(GDBusConnection *connection,
if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &info[0]) const gchar *sender,
|| !dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, const GVariant *parameters,
&info[1]) GDBusMethodInvocation *invocation)
|| !dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, {
&info[2]) printf("GetCapabilities\n");
|| !dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, GVariantBuilder *builder;
&info[3])) { GVariant *value;
fprintf(stderr, "Unable to fill arguments");
return; builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
g_variant_builder_add (builder, "s", "actions");
g_variant_builder_add (builder, "s", "body");
value = g_variant_new ("as", builder);
g_variant_builder_unref (builder);
g_dbus_method_invocation_return_value(invocation, value);
g_dbus_connection_flush(connection, NULL, NULL, NULL);
g_variant_unref(value);
}
static void onNotify(GDBusConnection *connection,
const gchar *sender,
GVariant *parameters,
GDBusMethodInvocation *invocation)
{
printf("Notify\n");
gchar *appname = NULL;
guint replaces_id = 0;
gchar *icon = NULL;
gchar *summary = NULL;
gchar *body = NULL;
Actions *actions = malloc(sizeof(actions));
gint timeout = -1;
/* hints */
gint urgency = 0;
gint progress = 0;
gchar *fgcolor = NULL;
gchar *bgcolor = NULL;
actions->actions = NULL;
actions->count = 0;
{
GVariantIter *iter = g_variant_iter_new(parameters);
GVariant *content;
GVariant *dict_value;
int idx = 0;
while ((content = g_variant_iter_next_value(iter))) {
switch (idx) {
case 0:
appname = g_variant_dup_string(content, NULL);
break;
case 1:
replaces_id = g_variant_get_uint32(content);
break;
case 2:
icon = g_variant_dup_string(content, NULL);
break;
case 3:
summary = g_variant_dup_string(content, NULL);
break;
case 4:
body = g_variant_dup_string(content, NULL);
break;
case 5:
actions->actions = g_variant_dup_strv(content, &(actions->count));
break;
case 6:
dict_value = g_variant_lookup_value(content, "urgency", G_VARIANT_TYPE_BYTE);
urgency = g_variant_get_byte(dict_value);
break;
case 7:
timeout = g_variant_get_int32(content);
break;
}
idx++;
}
g_variant_iter_free(iter);
} }
dbus_serial++; printf("appname: %s\n", appname);
if (!dbus_connection_send(dbus_conn, reply, &dbus_serial)) { printf("replaces_id: %i\n", replaces_id);
fprintf(stderr, "Out Of Memory!\n"); printf("icon: %s\n", icon);
exit(EXIT_FAILURE); printf("summary: %s\n", summary);
} printf("body: %s\n", body);
dbus_connection_flush(dbus_conn); printf("timeout: %i\n", timeout);
printf("nactions: %d\n", actions->count);
dbus_message_unref(reply); fflush(stdout);
if (timeout > 0) {
/* do some rounding */
timeout = (timeout + 500) / 1000;
if (timeout < 1) {
timeout = 1;
}
}
notification *n = malloc(sizeof (notification));
n->appname = appname;
n->summary = summary;
n->body = body;
n->icon = icon;
n->timeout = timeout;
n->progress = (progress < 0 || progress > 100) ? 0 : progress + 1;
n->urgency = urgency;
n->dbus_client = strdup(sender);
n->actions = actions;
for (int i = 0; i < ColLast; i++) {
n->color_strings[i] = NULL;
}
n->color_strings[ColFG] = fgcolor;
n->color_strings[ColBG] = bgcolor;
int id = init_notification(n, replaces_id);
GVariant *reply = g_variant_new ("(u)", id);
g_dbus_method_invocation_return_value(invocation, reply);
g_dbus_connection_flush(connection, NULL, NULL, NULL);
g_variant_unref(reply);
run(NULL);
}
static void onCloseNotification(GDBusConnection *connection,
const gchar *sender,
const GVariant *parameters,
GDBusMethodInvocation *invocation)
{
printf("CloseNotification\n");
}
static void onGetServerInformation(GDBusConnection *connection,
const gchar *sender,
const GVariant *parameters,
GDBusMethodInvocation *invocation)
{
printf("GetServerInformation\n");
GVariant *value;
value = g_variant_new ("(ssss)", "dunst", "knopwob", VERSION, "2013");
g_dbus_method_invocation_return_value(invocation, value);
g_dbus_connection_flush(connection, NULL, NULL, NULL);
printf("End GetServerInformation\n");
} }
void notificationClosed(notification * n, int reason) void notificationClosed(notification * n, int reason)
{ {
DBusMessage *dmsg; printf("notificationClosed\n");
DBusMessageIter args;
int id;
if (n == NULL || n->dbus_client == NULL) {
return;
}
id = n->id;
dmsg =
dbus_message_new_signal("/org/freedesktop/Notifications",
"org.freedesktop.Notifications",
"NotificationClosed");
dbus_message_iter_init_append(dmsg, &args);
dbus_message_iter_append_basic(&args, DBUS_TYPE_UINT32, &id);
dbus_message_iter_append_basic(&args, DBUS_TYPE_UINT32, &reason);
dbus_message_set_destination(dmsg, n->dbus_client);
dbus_connection_send(dbus_conn, dmsg, &dbus_serial);
dbus_message_unref(dmsg);
dbus_connection_flush(dbus_conn);
} }
void notify(DBusMessage * dmsg) static const GDBusInterfaceVTable interface_vtable =
{ {
DBusMessage *reply; handle_method_call
DBusMessageIter args; };
DBusMessageIter hints;
DBusMessageIter hint;
char *hint_name;
int i; static void on_bus_acquired(GDBusConnection *connection,
int id; const gchar *name,
const char *appname = NULL; gpointer user_data)
const char *summary = NULL; {
const char *body = NULL; guint registration_id;
const char *icon = NULL;
const char *fgcolor = NULL;
const char *bgcolor = NULL;
int urgency = 1;
int progress = -1;
notification *n = malloc(sizeof(notification));
dbus_uint32_t replaces_id = 0;
dbus_int32_t expires = -1;
dbus_serial++; registration_id = g_dbus_connection_register_object( connection,
dbus_message_iter_init(dmsg, &args); "/org/freedesktop/Notifications",
introspection_data->interfaces[0],
&interface_vtable,
NULL,
NULL,
NULL);
_extract_basic(DBUS_TYPE_STRING, &args, &appname); if (! registration_id > 0) {
fprintf(stderr, "Unable to register\n");
dbus_message_iter_next(&args); exit(1);
_extract_basic(DBUS_TYPE_UINT32, &args, &replaces_id);
dbus_message_iter_next(&args);
_extract_basic(DBUS_TYPE_STRING, &args, &icon);
dbus_message_iter_next(&args);
_extract_basic(DBUS_TYPE_STRING, &args, &summary);
dbus_message_iter_next(&args);
_extract_basic(DBUS_TYPE_STRING, &args, &body);
dbus_message_iter_next(&args);
dbus_message_iter_next(&args);
dbus_message_iter_recurse(&args, &hints);
dbus_message_iter_next(&args);
_extract_basic(DBUS_TYPE_INT32, &args, &expires);
while (dbus_message_iter_get_arg_type(&hints) != DBUS_TYPE_INVALID) {
dbus_message_iter_recurse(&hints, &hint);
while (dbus_message_iter_get_arg_type(&hint) !=
DBUS_TYPE_INVALID) {
if (dbus_message_iter_get_arg_type(&hint) !=
DBUS_TYPE_STRING) {
dbus_message_iter_next(&hint);
continue;
}
dbus_message_iter_get_basic(&hint, &hint_name);
_extract_hint(DBUS_TYPE_BYTE, "urgency", hint_name,
&hint, &urgency);
_extract_hint(DBUS_TYPE_STRING, "fgcolor", hint_name,
&hint, &fgcolor);
_extract_hint(DBUS_TYPE_STRING, "bgcolor", hint_name,
&hint, &bgcolor);
_extract_hint(DBUS_TYPE_INT32, "value", hint_name,
&hint, &progress);
if (!progress)
_extract_hint(DBUS_TYPE_UINT32, "value",
hint_name, &hint, &progress);
dbus_message_iter_next(&hint);
}
dbus_message_iter_next(&hints);
} }
if (expires > 0) {
/* do some rounding */
expires = (expires + 500) / 1000;
if (expires < 1) {
expires = 1;
}
}
n->appname = appname != NULL ? g_strdup(appname) : "";
n->summary = summary != NULL ? g_strdup(summary) : "";
n->body = body != NULL ? g_strdup(body) : "";
n->icon = icon != NULL ? g_strdup(icon) : "";
n->timeout = expires;
n->progress = (progress < 0 || progress > 100) ? 0 : progress + 1;
n->urgency = urgency;
n->dbus_client = g_strdup(dbus_message_get_sender(dmsg));
for (i = 0; i < ColLast; i++) {
n->color_strings[i] = NULL;
}
n->color_strings[ColFG] = fgcolor == NULL ? NULL : g_strdup(fgcolor);
n->color_strings[ColBG] = bgcolor == NULL ? NULL : g_strdup(bgcolor);
id = init_notification(n, replaces_id);
if (id > 0)
map_win();
reply = dbus_message_new_method_return(dmsg);
dbus_message_iter_init_append(reply, &args);
dbus_message_iter_append_basic(&args, DBUS_TYPE_UINT32, &id);
dbus_connection_send(dbus_conn, reply, &dbus_serial);
dbus_message_unref(reply);
} }
/* vim: set ts=8 sw=8 tw=0: */ static void on_name_acquired(GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
}
static void on_name_lost(GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
fprintf(stderr, "Name Lost\n");
exit(1);
}
int initdbus(void)
{
guint owner_id;
g_type_init();
introspection_data = g_dbus_node_info_new_for_xml(introspection_xml,
NULL);
owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
"org.freedesktop.Notifications",
G_BUS_NAME_OWNER_FLAGS_NONE,
on_bus_acquired,
on_name_acquired,
on_name_lost,
NULL,
NULL);
return owner_id;
}

View File

@ -5,12 +5,8 @@
#include <dbus/dbus.h> #include <dbus/dbus.h>
void initdbus(void); int initdbus(void);
void dbus_poll(int timeout); /* void dbus_poll(int timeout); */
void notify(DBusMessage * msg);
void getCapabilities(DBusMessage * dmsg);
void closeNotification(DBusMessage * dmsg);
void getServerInformation(DBusMessage * dmsg);
void notificationClosed(notification * n, int reason); void notificationClosed(notification * n, int reason);
#endif #endif