Skip to content

Commit

Permalink
Move dbus service tracking helpers from display plugin to mce-dbus
Browse files Browse the repository at this point in the history
There are multitudes of local dbus service tracking variants scattered
around mce code base.

The lipstick state is needed by tklock core module and provided by
in theory optional display plugin.

Move the name owner tracking implemented in display plugin to mce-dbus
so that it can be used as common implementation for tracking all dbus
services that are essential for mce operation. Initially use it for
tracking availability of lipstick and compositor service.
  • Loading branch information
spiiroin committed Jan 22, 2015
1 parent 6d8b6f0 commit 27dc905
Show file tree
Hide file tree
Showing 3 changed files with 393 additions and 310 deletions.
326 changes: 326 additions & 0 deletions mce-dbus.c
Expand Up @@ -3163,6 +3163,326 @@ static gboolean introspect_dbus_cb(DBusMessage *const req)
return TRUE;
}

/* ========================================================================= *
* DBUS_NAME_OWNER_TRACKING
* ========================================================================= */

static void mce_dbus_nameowner_changed(const char *name, const char *prev, const char *curr);
static DBusHandlerResult mce_dbus_nameowner_filter_cb(DBusConnection *con, DBusMessage *msg, void *user_data);
static void mce_dbus_nameowner_query_rsp(DBusPendingCall *pending, void *user_data);
static void mce_dbus_nameowner_query_req(const char *name);
static char *mce_dbus_nameowner_watch(const char *name);
static void mce_dbus_nameowner_unwatch(char *rule);

static void mce_dbus_nameowner_init(void);
static void mce_dbus_nameowner_quit(void);

/** Format string for constructing name owner lost match rules */
static const char mce_dbus_nameowner_rule_fmt[] =
"type='signal'"
",interface='"DBUS_INTERFACE_DBUS"'"
",member='NameOwnerChanged'"
",arg0='%s'"
;

/** D-Bus connection */
static DBusConnection *mce_dbus_nameowner_bus = 0;

static void mdy_stm_compositor_name_owner_changed(const char *name,
const char *prev,
const char *curr)
{
(void)name, (void)prev;

/* broadcast within mce */
bool available = (curr && *curr);
execute_datapipe(&compositor_available_pipe,
GINT_TO_POINTER(available),
USE_INDATA, CACHE_INDATA);
}

/** react to systemui availability changes
*/
static void mdy_stm_lipstick_name_owner_changed(const char *name,
const char *prev,
const char *curr)
{
(void)name, (void)prev;

/* broadcast within mce */
bool available = (curr && *curr);
execute_datapipe(&lipstick_available_pipe,
GINT_TO_POINTER(available),
USE_INDATA, CACHE_INDATA);
}

/** Lookup table of D-Bus names to watch */
static struct
{
const char *name;
char *rule;
void (*notify)(const char *name, const char *prev, const char *curr);
char *owner;
} mce_dbus_nameowner_lut[] =
{
{
.name = COMPOSITOR_SERVICE,
.notify = mdy_stm_compositor_name_owner_changed,
},
{
/* Note: due to lipstick==compositor assumption lipstick
* service name must be probed after compositor */
.name = LIPSTICK_SERVICE,
.notify = mdy_stm_lipstick_name_owner_changed,
},
{
.name = 0,
}
};

/** Call NameOwner changed callback from mce_dbus_nameowner_lut
*
* @param name D-Bus name that changed owner
* @param prev D-Bus name of the previous owner
* @param curr D-Bus name of the current owner
*/
static void
mce_dbus_nameowner_changed(const char *name, const char *prev, const char *curr)
{
for( int i = 0; mce_dbus_nameowner_lut[i].name; ++i ) {
if( strcmp(mce_dbus_nameowner_lut[i].name, name) )
continue;

// change cached name owner
free(mce_dbus_nameowner_lut[i].owner);
if( curr && *curr )
mce_dbus_nameowner_lut[i].owner = strdup(curr);
else
mce_dbus_nameowner_lut[i].owner = 0;

// notify
mce_dbus_nameowner_lut[i].notify(name, prev, curr);
}
}

/** Get current name owner for tracked services
*
* @param name Well known D-Bus name
*
* @return owner name or NULL
*/
const char *
mce_dbus_nameowner_get(const char *name)
{
const char *owner = 0;
for( int i = 0; mce_dbus_nameowner_lut[i].name; ++i ) {
if( strcmp(mce_dbus_nameowner_lut[i].name, name) )
continue;

owner = mce_dbus_nameowner_lut[i].owner;
break;
}
return owner;
}

/** Call back for handling asynchronous client verification via GetNameOwner
*
* @param pending control structure for asynchronous d-bus methdod call
* @param user_data dbus_name of the client as void poiter
*/
static
void
mce_dbus_nameowner_query_rsp(DBusPendingCall *pending, void *user_data)
{
const char *name = user_data;
const char *owner = 0;
DBusMessage *rsp = 0;
DBusError err = DBUS_ERROR_INIT;

if( !(rsp = dbus_pending_call_steal_reply(pending)) )
goto EXIT;

if( dbus_set_error_from_message(&err, rsp) ||
!dbus_message_get_args(rsp, &err,
DBUS_TYPE_STRING, &owner,
DBUS_TYPE_INVALID) )
{
if( strcmp(err.name, DBUS_ERROR_NAME_HAS_NO_OWNER) ) {
mce_log(LL_WARN, "%s: %s", err.name, err.message);
}
}

mce_dbus_nameowner_changed(name, "", owner ?: "");

EXIT:
if( rsp ) dbus_message_unref(rsp);
dbus_error_free(&err);
}

/** Verify that a client exists via an asynchronous GetNameOwner method call
*
* @param name the dbus name who's owner we wish to know
*/
static
void
mce_dbus_nameowner_query_req(const char *name)
{
DBusMessage *req = 0;
DBusPendingCall *pc = 0;
char *key = 0;

req = dbus_message_new_method_call(DBUS_SERVICE_DBUS,
DBUS_PATH_DBUS,
DBUS_INTERFACE_DBUS,
"GetNameOwner");
dbus_message_append_args(req,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_INVALID);

if( !dbus_connection_send_with_reply(mce_dbus_nameowner_bus, req, &pc, -1) )
goto EXIT;

if( !pc )
goto EXIT;

key = strdup(name);

if( !dbus_pending_call_set_notify(pc, mce_dbus_nameowner_query_rsp, key, free) )
goto EXIT;

// key string is owned by pending call
key = 0;

EXIT:
free(key);

if( pc ) dbus_pending_call_unref(pc);
if( req ) dbus_message_unref(req);
}

/** D-Bus message filter for handling NameOwnerChanged signals
*
* @param con (not used)
* @param msg message to be acted upon
* @param user_data (not used)
*
* @return DBUS_HANDLER_RESULT_NOT_YET_HANDLED (other filters see the msg too)
*/
static
DBusHandlerResult
mce_dbus_nameowner_filter_cb(DBusConnection *con, DBusMessage *msg, void *user_data)
{
(void)user_data;
(void)con;

DBusHandlerResult res = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;

const char *name = 0;
const char *prev = 0;
const char *curr = 0;

DBusError err = DBUS_ERROR_INIT;

if( !dbus_message_is_signal(msg, DBUS_INTERFACE_DBUS,
"NameOwnerChanged") )
goto EXIT;

if( !dbus_message_get_args(msg, &err,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_STRING, &prev,
DBUS_TYPE_STRING, &curr,
DBUS_TYPE_INVALID) ) {
mce_log(LL_WARN, "%s: %s", err.name, err.message);
goto EXIT;
}

mce_dbus_nameowner_changed(name, prev, curr);
EXIT:
dbus_error_free(&err);
return res;
}

/** Create a match rule and add it to D-Bus daemon side
*
* Use mce_dbus_nameowner_unwatch() to cancel.
*
* @param name D-Bus name that changed owner
*
* @return rule that was sent to the D-Bus daemon
*/
static char *
mce_dbus_nameowner_watch(const char *name)
{
char *rule = g_strdup_printf(mce_dbus_nameowner_rule_fmt, name);
dbus_bus_add_match(mce_dbus_nameowner_bus, rule, 0);
return rule;
}

/** Remove a match rule from D-Bus daemon side and free it
*
* @param rule obtained from mce_dbus_nameowner_watch()
*/
static void mce_dbus_nameowner_unwatch(char *rule)
{
if( rule ) {
dbus_bus_remove_match(mce_dbus_nameowner_bus, rule, 0);
g_free(rule);
}
}

/** Start D-Bus name owner tracking
*/
static void
mce_dbus_nameowner_init(void)
{
/* Get D-Bus system bus connection */
if( !(mce_dbus_nameowner_bus = dbus_connection_get()) ) {
goto EXIT;
}

dbus_connection_add_filter(mce_dbus_nameowner_bus,
mce_dbus_nameowner_filter_cb, 0, 0);

for( int i = 0; mce_dbus_nameowner_lut[i].name; ++i ) {
mce_dbus_nameowner_lut[i].rule = mce_dbus_nameowner_watch(mce_dbus_nameowner_lut[i].name);
mce_dbus_nameowner_query_req(mce_dbus_nameowner_lut[i].name);
}
EXIT:
return;
}

/** Stop D-Bus name owner tracking
*/

static void
mce_dbus_nameowner_quit(void)
{
if( !mce_dbus_nameowner_bus )
goto EXIT;

/* remove filter callback */
dbus_connection_remove_filter(mce_dbus_nameowner_bus,
mce_dbus_nameowner_filter_cb, 0);

/* remove name owner matches */
for( int i = 0; mce_dbus_nameowner_lut[i].name; ++i ) {
mce_dbus_nameowner_unwatch(mce_dbus_nameowner_lut[i].rule),
mce_dbus_nameowner_lut[i].rule = 0;

free(mce_dbus_nameowner_lut[i].owner),
mce_dbus_nameowner_lut[i].owner = 0;
}

// TODO: we should keep track of async name owner calls
// and cancel them at this point

dbus_connection_unref(mce_dbus_nameowner_bus), mce_dbus_nameowner_bus = 0;

EXIT:
return;

}

/* ========================================================================= *
* LOAD/UNLOAD
* ========================================================================= */
Expand Down Expand Up @@ -3264,6 +3584,9 @@ gboolean mce_dbus_init(const gboolean systembus)
/* Register callbacks that are handled inside mce-dbus.c */
mce_dbus_handler_register_array(mce_dbus_handlers);

/* Start tracking essential services */
mce_dbus_nameowner_init();

status = TRUE;

EXIT:
Expand All @@ -3276,6 +3599,9 @@ gboolean mce_dbus_init(const gboolean systembus)
*/
void mce_dbus_exit(void)
{
/* Stop tracking essential services */
mce_dbus_nameowner_quit();

/* Remove message handlers */
dbus_quit_message_handler();

Expand Down
21 changes: 21 additions & 0 deletions mce-dbus.h
Expand Up @@ -27,6 +27,25 @@

#include <dbus/dbus.h>

/* ========================================================================= *
* COMPOSITOR DBUS SERVICE
* ========================================================================= */

#define COMPOSITOR_SERVICE "org.nemomobile.compositor"
#define COMPOSITOR_PATH "/"
#define COMPOSITOR_IFACE "org.nemomobile.compositor"

/* Enabling/disabling display updates via compositor service */
#define COMPOSITOR_SET_UPDATES_ENABLED "setUpdatesEnabled"

/* ========================================================================= *
* LIPSTICK DBUS SERVICE
* ========================================================================= */

#define LIPSTICK_SERVICE "org.nemomobile.lipstick"
#define LIPSTICK_PATH "/"
#define LIPSTICK_IFACE "org.nemomobile.lipstick"

DBusConnection *dbus_connection_get(void);

DBusMessage *dbus_new_signal(const gchar *const path,
Expand Down Expand Up @@ -124,4 +143,6 @@ const char *mce_dbus_get_message_sender_ident(DBusMessage *msg);
typedef void (*mce_dbus_pid_notify_t)(const char *name, int pid);
void mce_dbus_get_pid_async(const char *name, mce_dbus_pid_notify_t cb);

const char *mce_dbus_nameowner_get(const char *name);

#endif /* _MCE_DBUS_H_ */

0 comments on commit 27dc905

Please sign in to comment.