mirror of
https://github.com/swaywm/sway.git
synced 2026-03-30 11:10:59 -04:00
Allow registering StatusNotifierItems by obj path
This commit impliments a KDE hidden feature where a SNI could be registered by object path instead of well-known name. This should allow libappindicator programs to work correctly under sway. See #1372
This commit is contained in:
parent
d85ad05fa8
commit
ad99d9dff8
4 changed files with 317 additions and 32 deletions
|
|
@ -9,6 +9,8 @@ struct StatusNotifierItem {
|
|||
char *name;
|
||||
/* Unique bus name, needed for determining signal origins */
|
||||
char *unique_name;
|
||||
/* Object path, useful for items not registerd by well known name */
|
||||
char *object_path;
|
||||
bool kde_special_snowflake;
|
||||
|
||||
cairo_surface_t *image;
|
||||
|
|
@ -31,6 +33,12 @@ void sni_icon_ref_free(struct sni_icon_ref *sni_ref);
|
|||
* May return `NULL` if `name` is not valid.
|
||||
*/
|
||||
struct StatusNotifierItem *sni_create(const char *name);
|
||||
/**
|
||||
* Same as sni_create, but takes an object path and unique name instead of
|
||||
* well-known name.
|
||||
*/
|
||||
struct StatusNotifierItem *sni_create_from_obj_path(const char *unique_name,
|
||||
const char *object_path);
|
||||
|
||||
/**
|
||||
* `item` must be a struct StatusNotifierItem *
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ static void send_icon_msg(struct StatusNotifierItem *item) {
|
|||
DBusPendingCall *pending;
|
||||
DBusMessage *message = dbus_message_new_method_call(
|
||||
item->name,
|
||||
"/StatusNotifierItem",
|
||||
item->object_path,
|
||||
"org.freedesktop.DBus.Properties",
|
||||
"Get");
|
||||
const char *iface;
|
||||
|
|
@ -285,7 +285,7 @@ static void send_icon_name_msg(struct StatusNotifierItem *item) {
|
|||
DBusPendingCall *pending;
|
||||
DBusMessage *message = dbus_message_new_method_call(
|
||||
item->name,
|
||||
"/StatusNotifierItem",
|
||||
item->object_path,
|
||||
"org.freedesktop.DBus.Properties",
|
||||
"Get");
|
||||
const char *iface;
|
||||
|
|
@ -324,7 +324,7 @@ void sni_activate(struct StatusNotifierItem *item, uint32_t x, uint32_t y) {
|
|||
: "org.freedesktop.StatusNotifierItem");
|
||||
DBusMessage *message = dbus_message_new_method_call(
|
||||
item->name,
|
||||
"/StatusNotifierItem",
|
||||
item->object_path,
|
||||
iface,
|
||||
"Activate");
|
||||
|
||||
|
|
@ -342,9 +342,10 @@ void sni_context_menu(struct StatusNotifierItem *item, uint32_t x, uint32_t y) {
|
|||
const char *iface =
|
||||
(item->kde_special_snowflake ? "org.kde.StatusNotifierItem"
|
||||
: "org.freedesktop.StatusNotifierItem");
|
||||
sway_log(L_INFO, "Activating context menu for item: (%s,%s)", item->name, item->object_path);
|
||||
DBusMessage *message = dbus_message_new_method_call(
|
||||
item->name,
|
||||
"/StatusNotifierItem",
|
||||
item->object_path,
|
||||
iface,
|
||||
"ContextMenu");
|
||||
|
||||
|
|
@ -363,7 +364,7 @@ void sni_secondary(struct StatusNotifierItem *item, uint32_t x, uint32_t y) {
|
|||
: "org.freedesktop.StatusNotifierItem");
|
||||
DBusMessage *message = dbus_message_new_method_call(
|
||||
item->name,
|
||||
"/StatusNotifierItem",
|
||||
item->object_path,
|
||||
iface,
|
||||
"SecondaryActivate");
|
||||
|
||||
|
|
@ -426,6 +427,8 @@ struct StatusNotifierItem *sni_create(const char *name) {
|
|||
struct StatusNotifierItem *item = malloc(sizeof(struct StatusNotifierItem));
|
||||
item->name = strdup(name);
|
||||
item->unique_name = NULL;
|
||||
// TODO use static str if the default path instead of all these god-damn strdups
|
||||
item->object_path = strdup("/StatusNotifierItem");
|
||||
item->image = NULL;
|
||||
item->dirty = false;
|
||||
|
||||
|
|
@ -449,6 +452,21 @@ struct StatusNotifierItem *sni_create(const char *name) {
|
|||
|
||||
return item;
|
||||
}
|
||||
struct StatusNotifierItem *sni_create_from_obj_path(const char *unique_name,
|
||||
const char *object_path) {
|
||||
struct StatusNotifierItem *item = malloc(sizeof(struct StatusNotifierItem));
|
||||
// XXX strdup-ing twice to avoid a double-free; see above todo
|
||||
item->name = strdup(unique_name);
|
||||
item->unique_name = strdup(unique_name);
|
||||
item->object_path = strdup(object_path);
|
||||
item->image = NULL;
|
||||
item->dirty = false;
|
||||
// If they're registering by obj-path they're a special snowflake
|
||||
item->kde_special_snowflake = true;
|
||||
|
||||
get_icon(item);
|
||||
return item;
|
||||
}
|
||||
/* Return 0 if `item` has a name of `str` */
|
||||
int sni_str_cmp(const void *_item, const void *_str) {
|
||||
const struct StatusNotifierItem *item = _item;
|
||||
|
|
@ -471,9 +489,8 @@ void sni_free(struct StatusNotifierItem *item) {
|
|||
return;
|
||||
}
|
||||
free(item->name);
|
||||
if (item->unique_name) {
|
||||
free(item->unique_name);
|
||||
}
|
||||
free(item->unique_name);
|
||||
free(item->object_path);
|
||||
if (item->image) {
|
||||
cairo_surface_destroy(item->image);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
static list_t *items = NULL;
|
||||
static list_t *hosts = NULL;
|
||||
static list_t *object_path_items = NULL;
|
||||
|
||||
/**
|
||||
* Describes the function of the StatusNotifierWatcher
|
||||
|
|
@ -18,6 +19,10 @@ static list_t *hosts = NULL;
|
|||
*
|
||||
* We also implement KDE's special snowflake protocol, it's like this but with
|
||||
* all occurrences 'freedesktop' replaced with 'kde'. There is no KDE introspect.
|
||||
*
|
||||
* We _also_ support registering items by object path (even though this is a
|
||||
* huge pain in the ass). Hosts that would like to subscribe to these items have
|
||||
* to go through the `org.swaywm.LessSuckyStatusNotifierWatcher` interface.
|
||||
*/
|
||||
static const char *interface_xml =
|
||||
"<!DOCTYPE node PUBLIC '-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'"
|
||||
|
|
@ -64,8 +69,59 @@ static const char *interface_xml =
|
|||
" <arg type='' name='service' direction='out'/>"
|
||||
" </signal>"
|
||||
" </interface>"
|
||||
" <interface name='org.swaywm.LessSuckyStatusNotifierWatcher'>"
|
||||
" <property name='RegisteredObjectPathItems' type='a(os)' access='read'/>"
|
||||
" <signal name='ObjPathItemRegistered'>"
|
||||
" <arg type='os' name='service' direction='out'/>"
|
||||
" </signal>"
|
||||
" </interface>"
|
||||
"</node>";
|
||||
|
||||
struct ObjPathItem {
|
||||
char *obj_path;
|
||||
char *unique_name;
|
||||
};
|
||||
|
||||
static void free_obj_path_item(struct ObjPathItem *item) {
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
free(item->unique_name);
|
||||
free(item->obj_path);
|
||||
free(item);
|
||||
}
|
||||
static struct ObjPathItem *create_obj_path_item(const char *unique_name, const char *obj_path) {
|
||||
struct ObjPathItem *item = malloc(sizeof(struct ObjPathItem));
|
||||
if (!item) {
|
||||
return NULL;
|
||||
}
|
||||
item->unique_name = strdup(unique_name);
|
||||
item->obj_path = strdup(obj_path);
|
||||
if (!item->unique_name || !item->obj_path) {
|
||||
free_obj_path_item(item);
|
||||
return NULL;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
/**
|
||||
* NOTE: This compare function does have ordering, this is because it has to
|
||||
* comapre two strings.
|
||||
*/
|
||||
static int obj_path_item_cmp(const void *_item1, const void *_item2) {
|
||||
const struct ObjPathItem *item1 = _item1;
|
||||
const struct ObjPathItem *item2 = _item2;
|
||||
if (strcmp(item1->unique_name,item2->unique_name) == 0 &&
|
||||
strcmp(item1->obj_path,item2->obj_path) == 0) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
static int obj_path_unique_name_cmp(const void *_item, const void *_unique_name) {
|
||||
const struct ObjPathItem *item = _item;
|
||||
const char *unique_name = _unique_name;
|
||||
return strcmp(item->unique_name, unique_name);
|
||||
}
|
||||
|
||||
static void host_registered_signal(DBusConnection *connection) {
|
||||
// Send one signal for each protocol
|
||||
DBusMessage *signal = dbus_message_new_signal(
|
||||
|
|
@ -128,6 +184,19 @@ static void item_unregistered_signal(DBusConnection *connection, const char *nam
|
|||
dbus_message_unref(signal);
|
||||
}
|
||||
|
||||
static void obj_path_item_registered_signal(DBusConnection *connection, const struct ObjPathItem *item) {
|
||||
DBusMessage *signal = dbus_message_new_signal(
|
||||
"/StatusNotifierWatcher",
|
||||
"org.swaywm.LessSuckyStatusNotifierWatcher",
|
||||
"ObjPathItemRegistered");
|
||||
dbus_message_append_args(signal,
|
||||
DBUS_TYPE_OBJECT_PATH, &item->obj_path,
|
||||
DBUS_TYPE_STRING, &item->unique_name,
|
||||
DBUS_TYPE_INVALID);
|
||||
dbus_connection_send(connection, signal, NULL);
|
||||
dbus_message_unref(signal);
|
||||
}
|
||||
|
||||
static void respond_to_introspect(DBusConnection *connection, DBusMessage *request) {
|
||||
DBusMessage *reply;
|
||||
|
||||
|
|
@ -147,28 +216,44 @@ static void register_item(DBusConnection *connection, DBusMessage *message) {
|
|||
if (!dbus_message_get_args(message, &error,
|
||||
DBUS_TYPE_STRING, &name,
|
||||
DBUS_TYPE_INVALID)) {
|
||||
sway_log(L_ERROR, "Error parsing method args: %s\n", error.message);
|
||||
sway_log(L_ERROR, "Error parsing method args: %s", error.message);
|
||||
}
|
||||
|
||||
sway_log(L_INFO, "RegisterStatusNotifierItem called with \"%s\"\n", name);
|
||||
sway_log(L_INFO, "RegisterStatusNotifierItem called with \"%s\"", name);
|
||||
|
||||
// Don't add duplicate or not real item
|
||||
if (!dbus_validate_bus_name(name, NULL)) {
|
||||
sway_log(L_INFO, "This item is not valid, we cannot keep track of it.");
|
||||
return;
|
||||
if (dbus_validate_path(name, NULL)) {
|
||||
// Item is registered by object path
|
||||
struct ObjPathItem *item =
|
||||
create_obj_path_item(dbus_message_get_sender(message), name);
|
||||
|
||||
// Add ObjPathItem
|
||||
if (list_seq_find(object_path_items, obj_path_item_cmp, item) != -1) {
|
||||
free_obj_path_item(item);
|
||||
return;
|
||||
}
|
||||
list_add(object_path_items, item);
|
||||
obj_path_item_registered_signal(connection, item);
|
||||
return;
|
||||
} else {
|
||||
sway_log(L_INFO, "This item is not valid, we cannot keep track of it.");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
|
||||
if (list_seq_find(items, (int (*)(const void *, const void *))strcmp, name) != -1) {
|
||||
return;
|
||||
}
|
||||
if (!dbus_bus_name_has_owner(connection, name, &error)) {
|
||||
return;
|
||||
}
|
||||
|
||||
list_add(items, strdup(name));
|
||||
item_registered_signal(connection, name);
|
||||
}
|
||||
|
||||
if (list_seq_find(items, (int (*)(const void *, const void *))strcmp, name) != -1) {
|
||||
return;
|
||||
}
|
||||
if (!dbus_bus_name_has_owner(connection, name, &error)) {
|
||||
return;
|
||||
}
|
||||
|
||||
list_add(items, strdup(name));
|
||||
item_registered_signal(connection, name);
|
||||
|
||||
// It's silly, but xembedsniproxy wants a reply for this function
|
||||
// It's silly, but clients want a reply for this function
|
||||
DBusMessage *reply = dbus_message_new_method_return(message);
|
||||
dbus_connection_send(connection, reply, NULL);
|
||||
dbus_message_unref(reply);
|
||||
|
|
@ -182,10 +267,10 @@ static void register_host(DBusConnection *connection, DBusMessage *message) {
|
|||
if (!dbus_message_get_args(message, &error,
|
||||
DBUS_TYPE_STRING, &name,
|
||||
DBUS_TYPE_INVALID)) {
|
||||
sway_log(L_ERROR, "Error parsing method args: %s\n", error.message);
|
||||
sway_log(L_ERROR, "Error parsing method args: %s", error.message);
|
||||
}
|
||||
|
||||
sway_log(L_INFO, "RegisterStatusNotifierHost called with \"%s\"\n", name);
|
||||
sway_log(L_INFO, "RegisterStatusNotifierHost called with \"%s\"", name);
|
||||
|
||||
// Don't add duplicate or not real host
|
||||
if (!dbus_validate_bus_name(name, NULL)) {
|
||||
|
|
@ -215,12 +300,12 @@ static void get_property(DBusConnection *connection, DBusMessage *message) {
|
|||
DBUS_TYPE_STRING, &interface,
|
||||
DBUS_TYPE_STRING, &property,
|
||||
DBUS_TYPE_INVALID)) {
|
||||
sway_log(L_ERROR, "Error parsing prop args: %s\n", error.message);
|
||||
sway_log(L_ERROR, "Error parsing prop args: %s", error.message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(property, "RegisteredStatusNotifierItems") == 0) {
|
||||
sway_log(L_INFO, "Replying with items\n");
|
||||
sway_log(L_INFO, "Replying with items");
|
||||
DBusMessage *reply;
|
||||
reply = dbus_message_new_method_return(message);
|
||||
DBusMessageIter iter;
|
||||
|
|
@ -279,6 +364,41 @@ static void get_property(DBusConnection *connection, DBusMessage *message) {
|
|||
DBUS_TYPE_INT32, &version);
|
||||
|
||||
dbus_message_iter_close_container(&iter, &sub);
|
||||
dbus_connection_send(connection, reply, NULL);
|
||||
dbus_message_unref(reply);
|
||||
} else if (strcmp(property, "RegisteredObjectPathItems") == 0) {
|
||||
sway_log(L_INFO, "Replying with ObjPathItems");
|
||||
DBusMessage *reply;
|
||||
reply = dbus_message_new_method_return(message);
|
||||
DBusMessageIter iter;
|
||||
DBusMessageIter variant;
|
||||
DBusMessageIter array;
|
||||
DBusMessageIter dstruct;
|
||||
|
||||
dbus_message_iter_init_append(reply, &iter);
|
||||
|
||||
dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
|
||||
"a(os)", &variant);
|
||||
dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
|
||||
"(os)", &array);
|
||||
|
||||
for (int i = 0; i < object_path_items->length; ++i) {
|
||||
struct ObjPathItem *item = object_path_items->items[i];
|
||||
|
||||
dbus_message_iter_open_container(&array,
|
||||
DBUS_TYPE_STRUCT, NULL, &dstruct);
|
||||
|
||||
dbus_message_iter_append_basic(&dstruct,
|
||||
DBUS_TYPE_OBJECT_PATH, item->obj_path);
|
||||
dbus_message_iter_append_basic(&dstruct,
|
||||
DBUS_TYPE_STRING, item->unique_name);
|
||||
|
||||
dbus_message_iter_close_container(&array, &dstruct);
|
||||
}
|
||||
|
||||
dbus_message_iter_close_container(&variant, &array);
|
||||
dbus_message_iter_close_container(&iter, &variant);
|
||||
|
||||
dbus_connection_send(connection, reply, NULL);
|
||||
dbus_message_unref(reply);
|
||||
}
|
||||
|
|
@ -289,6 +409,8 @@ static void set_property(DBusConnection *connection, DBusMessage *message) {
|
|||
return;
|
||||
}
|
||||
|
||||
// TODO clean me up please or get rid of me
|
||||
// also add LessSuckyStatusNotifierWatcher props
|
||||
static void get_all(DBusConnection *connection, DBusMessage *message) {
|
||||
DBusMessage *reply;
|
||||
reply = dbus_message_new_method_return(message);
|
||||
|
|
@ -400,6 +522,8 @@ static DBusHandlerResult signal_handler(DBusConnection *connection,
|
|||
const char *old_owner;
|
||||
const char *new_owner;
|
||||
int index;
|
||||
bool found_obj_path_item = false;
|
||||
|
||||
if (!dbus_message_get_args(message, NULL,
|
||||
DBUS_TYPE_STRING, &name,
|
||||
DBUS_TYPE_STRING, &old_owner,
|
||||
|
|
@ -427,6 +551,17 @@ static DBusHandlerResult signal_handler(DBusConnection *connection,
|
|||
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
while ((index = list_seq_find(object_path_items, obj_path_unique_name_cmp, name)) != -1) {
|
||||
found_obj_path_item = true;
|
||||
struct ObjPathItem *item = object_path_items->items[index];
|
||||
sway_log(L_INFO, "ObjPathItem lost %s", item->obj_path);
|
||||
list_del(object_path_items, index);
|
||||
free_obj_path_item(item);
|
||||
}
|
||||
if (found_obj_path_item) {
|
||||
item_unregistered_signal(connection, name);
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
}
|
||||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||
}
|
||||
|
|
@ -446,6 +581,7 @@ int init_sni_watcher() {
|
|||
|
||||
items = create_list();
|
||||
hosts = create_list();
|
||||
object_path_items = create_list();
|
||||
|
||||
int status = dbus_bus_request_name(conn, "org.freedesktop.StatusNotifierWatcher",
|
||||
DBUS_NAME_FLAG_REPLACE_EXISTING,
|
||||
|
|
@ -456,7 +592,7 @@ int init_sni_watcher() {
|
|||
sway_log(L_INFO, "Could not get watcher name, it may start later");
|
||||
}
|
||||
if (dbus_error_is_set(&error)) {
|
||||
sway_log(L_ERROR, "dbus err getting watcher name: %s\n", error.message);
|
||||
sway_log(L_ERROR, "dbus err getting watcher name: %s", error.message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -469,7 +605,7 @@ int init_sni_watcher() {
|
|||
sway_log(L_INFO, "Could not get kde watcher name, it may start later");
|
||||
}
|
||||
if (dbus_error_is_set(&error)) {
|
||||
sway_log(L_ERROR, "dbus err getting kde watcher name: %s\n", error.message);
|
||||
sway_log(L_ERROR, "dbus err getting kde watcher name: %s", error.message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -477,7 +613,7 @@ int init_sni_watcher() {
|
|||
"/StatusNotifierWatcher",
|
||||
&vtable, NULL, &error);
|
||||
if (dbus_error_is_set(&error)) {
|
||||
sway_log(L_ERROR, "dbus_err: %s\n", error.message);
|
||||
sway_log(L_ERROR, "dbus_err: %s", error.message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -102,6 +102,70 @@ bail:
|
|||
dbus_pending_call_unref(pending);
|
||||
return;
|
||||
}
|
||||
static void get_obj_items_reply(DBusPendingCall *pending, void *_data) {
|
||||
DBusMessage *reply = dbus_pending_call_steal_reply(pending);
|
||||
|
||||
if (!reply) {
|
||||
sway_log(L_ERROR, "Got no object path items reply from sni watcher");
|
||||
goto bail;
|
||||
}
|
||||
|
||||
int message_type = dbus_message_get_type(reply);
|
||||
|
||||
if (message_type == DBUS_MESSAGE_TYPE_ERROR) {
|
||||
char *msg;
|
||||
|
||||
dbus_message_get_args(reply, NULL,
|
||||
DBUS_TYPE_STRING, &msg,
|
||||
DBUS_TYPE_INVALID);
|
||||
|
||||
sway_log(L_ERROR, "Message is error: %s", msg);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
DBusMessageIter iter;
|
||||
DBusMessageIter variant;
|
||||
DBusMessageIter array;
|
||||
DBusMessageIter dstruct;
|
||||
|
||||
dbus_message_iter_init(reply, &iter);
|
||||
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
|
||||
sway_log(L_ERROR, "Replyed with wrong type, not v(a(os))");
|
||||
goto bail;
|
||||
}
|
||||
dbus_message_iter_recurse(&iter, &variant);
|
||||
if (strcmp(dbus_message_iter_get_signature(&variant), "a(os)") != 0) {
|
||||
sway_log(L_ERROR, "Replyed with wrong type not a(os)");
|
||||
goto bail;
|
||||
}
|
||||
|
||||
int len = dbus_message_iter_get_element_count(&variant);
|
||||
|
||||
dbus_message_iter_recurse(&variant, &array);
|
||||
for (int i = 0; i < len; i++) {
|
||||
const char *object_path;
|
||||
const char *unique_name;
|
||||
|
||||
dbus_message_iter_recurse(&array, &dstruct);
|
||||
|
||||
dbus_message_iter_get_basic(&dstruct, &object_path);
|
||||
dbus_message_iter_get_basic(&dstruct, &unique_name);
|
||||
|
||||
struct StatusNotifierItem *item =
|
||||
sni_create_from_obj_path(unique_name, object_path);
|
||||
|
||||
if (item) {
|
||||
sway_log(L_DEBUG, "Item registered with host: %s", unique_name);
|
||||
list_add(tray->items, item);
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
bail:
|
||||
dbus_message_unref(reply);
|
||||
dbus_pending_call_unref(pending);
|
||||
}
|
||||
|
||||
static void get_items() {
|
||||
DBusPendingCall *pending;
|
||||
DBusMessage *message = dbus_message_new_method_call(
|
||||
|
|
@ -127,6 +191,28 @@ static void get_items() {
|
|||
}
|
||||
|
||||
dbus_pending_call_set_notify(pending, get_items_reply, NULL, NULL);
|
||||
|
||||
message = dbus_message_new_method_call(
|
||||
"org.freedesktop.StatusNotifierWatcher",
|
||||
"/StatusNotifierWatcher",
|
||||
"org.freedesktop.DBus.Properties",
|
||||
"Get");
|
||||
|
||||
iface = "org.swaywm.LessSuckyStatusNotifierWatcher";
|
||||
prop = "RegisteredObjectPathItems";
|
||||
dbus_message_append_args(message,
|
||||
DBUS_TYPE_STRING, &iface,
|
||||
DBUS_TYPE_STRING, &prop,
|
||||
DBUS_TYPE_INVALID);
|
||||
|
||||
status = dbus_connection_send_with_reply(conn, message, &pending, -1);
|
||||
dbus_message_unref(message);
|
||||
|
||||
if (!(pending || status)) {
|
||||
sway_log(L_ERROR, "Could not get items");
|
||||
return;
|
||||
}
|
||||
dbus_pending_call_set_notify(pending, get_obj_items_reply, NULL, NULL);
|
||||
}
|
||||
|
||||
static DBusHandlerResult signal_handler(DBusConnection *connection,
|
||||
|
|
@ -162,11 +248,14 @@ static DBusHandlerResult signal_handler(DBusConnection *connection,
|
|||
}
|
||||
|
||||
int index;
|
||||
if ((index = list_seq_find(tray->items, sni_str_cmp, name)) != -1) {
|
||||
bool found_item = false;
|
||||
while ((index = list_seq_find(tray->items, sni_str_cmp, name)) != -1) {
|
||||
found_item = true;
|
||||
sni_free(tray->items->items[index]);
|
||||
list_del(tray->items, index);
|
||||
dirty = true;
|
||||
} else {
|
||||
}
|
||||
if (found_item == false) {
|
||||
// If it's not in our list, then our list is incorrect.
|
||||
// Fetch all items again
|
||||
sway_log(L_INFO, "Host item list incorrect, refreshing");
|
||||
|
|
@ -188,6 +277,32 @@ static DBusHandlerResult signal_handler(DBusConnection *connection,
|
|||
get_icon(item);
|
||||
}
|
||||
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
} else if (dbus_message_is_signal(message,
|
||||
"org.swaywm.LessSuckyStatusNotifierWatcher",
|
||||
"ObjPathItemRegistered")) {
|
||||
const char *object_path;
|
||||
const char *unique_name;
|
||||
if (!dbus_message_get_args(message, NULL,
|
||||
DBUS_TYPE_OBJECT_PATH, &object_path,
|
||||
DBUS_TYPE_STRING, &unique_name,
|
||||
DBUS_TYPE_INVALID)) {
|
||||
sway_log(L_ERROR, "Error getting ObjPathItemRegistered args");
|
||||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||
}
|
||||
|
||||
// TODO allow one unique name to have multiple items
|
||||
if (list_seq_find(tray->items, sni_str_cmp, unique_name) == -1) {
|
||||
struct StatusNotifierItem *item =
|
||||
sni_create_from_obj_path(unique_name,
|
||||
object_path);
|
||||
|
||||
if (item) {
|
||||
list_add(tray->items, item);
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||
|
|
@ -255,6 +370,15 @@ static int init_host() {
|
|||
sway_log(L_ERROR, "dbus_err: %s", error.message);
|
||||
return -1;
|
||||
}
|
||||
dbus_bus_add_match(conn,
|
||||
"type='signal',\
|
||||
sender='org.freedesktop.StatusNotifierWatcher',\
|
||||
member='ObjPathItemRegistered'",
|
||||
&error);
|
||||
if (dbus_error_is_set(&error)) {
|
||||
sway_log(L_ERROR, "dbus_err: %s", error.message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// SNI matches
|
||||
dbus_bus_add_match(conn,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue