diff --git a/include/swaybar/tray/item.h b/include/swaybar/tray/item.h index 9bba7951..4238bdb8 100644 --- a/include/swaybar/tray/item.h +++ b/include/swaybar/tray/item.h @@ -35,6 +35,10 @@ struct swaybar_sni { bool item_is_menu; char *menu; char *icon_theme_path; // non-standard KDE property + + sd_bus_slot *new_icon_slot; + sd_bus_slot *new_attention_icon_slot; + sd_bus_slot *new_status_slot; }; struct swaybar_sni *create_sni(char *id, struct swaybar_tray *tray); diff --git a/swaybar/main.c b/swaybar/main.c index 06238c62..fa99b1ba 100644 --- a/swaybar/main.c +++ b/swaybar/main.c @@ -76,7 +76,7 @@ int main(int argc, char **argv) { if (debug) { wlr_log_init(WLR_DEBUG, NULL); } else { - wlr_log_init(WLR_ERROR, NULL); + wlr_log_init(WLR_INFO, NULL); } if (!swaybar.id) { diff --git a/swaybar/tray/host.c b/swaybar/tray/host.c index 30339fec..cc8dd188 100644 --- a/swaybar/tray/host.c +++ b/swaybar/tray/host.c @@ -21,7 +21,7 @@ static int cmp_sni_id(const void *item, const void *cmp_to) { static void add_sni(struct swaybar_tray *tray, char *id) { int idx = list_seq_find(tray->items, cmp_sni_id, id); if (idx == -1) { - wlr_log(WLR_DEBUG, "Registering Status Notifier Item '%s'", id); + wlr_log(WLR_INFO, "Registering Status Notifier Item '%s'", id); struct swaybar_sni *sni = create_sni(id, tray); if (sni) { list_add(tray->items, sni); @@ -54,7 +54,7 @@ static int handle_sni_unregistered(sd_bus_message *msg, void *data, struct swaybar_tray *tray = data; int idx = list_seq_find(tray->items, cmp_sni_id, id); if (idx != -1) { - wlr_log(WLR_DEBUG, "Unregistering Status Notifier Item '%s'", id); + wlr_log(WLR_INFO, "Unregistering Status Notifier Item '%s'", id); destroy_sni(tray->items->items[idx]); list_del(tray->items, idx); set_bar_dirty(tray->bar); diff --git a/swaybar/tray/item.c b/swaybar/tray/item.c index 41cacd16..0833dcb9 100644 --- a/swaybar/tray/item.c +++ b/swaybar/tray/item.c @@ -19,7 +19,7 @@ // TODO menu static bool sni_ready(struct swaybar_sni *sni) { - return sni->status && (sni->status[0] == 'N' ? + return sni->status && (sni->status[0] == 'N' ? // NeedsAttention sni->attention_icon_name || sni->attention_icon_pixmap : sni->icon_name || sni->icon_pixmap); } @@ -35,11 +35,12 @@ static int read_pixmap(sd_bus_message *msg, struct swaybar_sni *sni, const char *prop, list_t **dest) { int ret = sd_bus_message_enter_container(msg, 'a', "(iiay)"); if (ret < 0) { - wlr_log(WLR_DEBUG, "Failed to read property %s: %s", prop, strerror(-ret)); + wlr_log(WLR_ERROR, "%s %s: %s", sni->watcher_id, prop, strerror(-ret)); return ret; } if (sd_bus_message_at_end(msg, 0)) { + wlr_log(WLR_DEBUG, "%s %s no. of icons = 0", sni->watcher_id, prop); return ret; } @@ -51,14 +52,14 @@ static int read_pixmap(sd_bus_message *msg, struct swaybar_sni *sni, while (!sd_bus_message_at_end(msg, 0)) { ret = sd_bus_message_enter_container(msg, 'r', "iiay"); if (ret < 0) { - wlr_log(WLR_DEBUG, "Failed to read property %s: %s", prop, strerror(-ret)); + wlr_log(WLR_ERROR, "%s %s: %s", sni->watcher_id, prop, strerror(-ret)); goto error; } int size; ret = sd_bus_message_read(msg, "ii", NULL, &size); if (ret < 0) { - wlr_log(WLR_DEBUG, "Failed to read property %s: %s", prop, strerror(-ret)); + wlr_log(WLR_ERROR, "%s %s: %s", sni->watcher_id, prop, strerror(-ret)); goto error; } @@ -66,7 +67,7 @@ static int read_pixmap(sd_bus_message *msg, struct swaybar_sni *sni, size_t npixels; ret = sd_bus_message_read_array(msg, 'y', &pixels, &npixels); if (ret < 0) { - wlr_log(WLR_DEBUG, "Failed to read property %s: %s", prop, strerror(-ret)); + wlr_log(WLR_ERROR, "%s %s: %s", sni->watcher_id, prop, strerror(-ret)); goto error; } @@ -78,7 +79,10 @@ static int read_pixmap(sd_bus_message *msg, struct swaybar_sni *sni, sd_bus_message_exit_container(msg); } + list_free_items_and_destroy(*dest); *dest = pixmaps; + wlr_log(WLR_DEBUG, "%s %s no. of icons = %d", sni->watcher_id, prop, + pixmaps->length); return ret; error: @@ -103,15 +107,15 @@ static int get_property_callback(sd_bus_message *msg, void *data, int ret; if (sd_bus_message_is_method_error(msg, NULL)) { - sd_bus_error err = *sd_bus_message_get_error(msg); - wlr_log(WLR_DEBUG, "Failed to get property %s: %s", prop, err.message); - ret = -sd_bus_error_get_errno(&err); + wlr_log(WLR_ERROR, "%s %s: %s", sni->watcher_id, prop, + sd_bus_message_get_error(msg)->message); + ret = sd_bus_message_get_errno(msg); goto cleanup; } ret = sd_bus_message_enter_container(msg, 'v', type); if (ret < 0) { - wlr_log(WLR_DEBUG, "Failed to read property %s: %s", prop, strerror(-ret)); + wlr_log(WLR_ERROR, "%s %s: %s", sni->watcher_id, prop, strerror(-ret)); goto cleanup; } @@ -121,14 +125,23 @@ static int get_property_callback(sd_bus_message *msg, void *data, goto cleanup; } } else { + if (*type == 's' || *type == 'o') { + free(*(char **)dest); + } + ret = sd_bus_message_read(msg, type, dest); if (ret < 0) { - wlr_log(WLR_DEBUG, "Failed to read property %s: %s", prop, - strerror(-ret)); + wlr_log(WLR_ERROR, "%s %s: %s", sni->watcher_id, prop, strerror(-ret)); goto cleanup; - } else if (*type == 's' || *type == 'o') { + } + + if (*type == 's' || *type == 'o') { char **str = dest; *str = strdup(*str); + wlr_log(WLR_DEBUG, "%s %s = '%s'", sni->watcher_id, prop, *str); + } else if (*type == 'b') { + wlr_log(WLR_DEBUG, "%s %s = %s", sni->watcher_id, prop, + *(bool *)dest ? "true" : "false"); } } @@ -152,62 +165,80 @@ static void sni_get_property_async(struct swaybar_sni *sni, const char *prop, sni->path, "org.freedesktop.DBus.Properties", "Get", get_property_callback, data, "ss", sni->interface, prop); if (ret < 0) { - wlr_log(WLR_DEBUG, "Failed to get property %s: %s", prop, strerror(-ret)); + wlr_log(WLR_ERROR, "%s %s: %s", sni->watcher_id, prop, strerror(-ret)); + } +} + +/* + * There is a quirk in sd-bus that in some systems, it is unable to get the + * well-known names on the bus, so it cannot identify if an incoming signal, + * which uses the sender's unique name, actually matches the callback's matching + * sender if the callback uses a well-known name, in which case it just calls + * the callback and hopes for the best, resulting in false positives. In the + * case of NewIcon & NewAttentionIcon, this doesn't affect anything, but it + * means that for NewStatus, if the SNI does not definitely match the sender, + * then the safe thing to do is to query the status independently. + * This function returns 1 if the SNI definitely matches the signal sender, + * which is returned by the calling function to indicate that signal matching + * can stop since it has already found the required callback, otherwise, it + * returns 0, which allows matching to continue. + */ +static int sni_check_msg_sender(struct swaybar_sni *sni, sd_bus_message *msg, + const char *signal) { + bool has_well_known_names = + sd_bus_creds_get_mask(sd_bus_message_get_creds(msg)) & SD_BUS_CREDS_WELL_KNOWN_NAMES; + if (sni->service[0] == ':' || has_well_known_names) { + wlr_log(WLR_DEBUG, "%s has new %s", sni->watcher_id, signal); + return 1; + } else { + wlr_log(WLR_DEBUG, "%s may have new %s", sni->watcher_id, signal); + return 0; } } static int handle_new_icon(sd_bus_message *msg, void *data, sd_bus_error *error) { struct swaybar_sni *sni = data; - wlr_log(WLR_DEBUG, "%s has new IconName", sni->watcher_id); - - free(sni->icon_name); - sni->icon_name = NULL; sni_get_property_async(sni, "IconName", "s", &sni->icon_name); - - list_free_items_and_destroy(sni->icon_pixmap); - sni->icon_pixmap = NULL; sni_get_property_async(sni, "IconPixmap", NULL, &sni->icon_pixmap); - - return 0; + return sni_check_msg_sender(sni, msg, "icon"); } static int handle_new_attention_icon(sd_bus_message *msg, void *data, sd_bus_error *error) { struct swaybar_sni *sni = data; - wlr_log(WLR_DEBUG, "%s has new AttentionIconName", sni->watcher_id); - - free(sni->attention_icon_name); - sni->attention_icon_name = NULL; sni_get_property_async(sni, "AttentionIconName", "s", &sni->attention_icon_name); - - list_free_items_and_destroy(sni->attention_icon_pixmap); - sni->attention_icon_pixmap = NULL; sni_get_property_async(sni, "AttentionIconPixmap", NULL, &sni->attention_icon_pixmap); - - return 0; + return sni_check_msg_sender(sni, msg, "attention icon"); } static int handle_new_status(sd_bus_message *msg, void *data, sd_bus_error *error) { - char *status; - int ret = sd_bus_message_read(msg, "s", &status); - if (ret < 0) { - wlr_log(WLR_DEBUG, "Failed to read new status message: %s", strerror(-ret)); + struct swaybar_sni *sni = data; + int ret = sni_check_msg_sender(sni, msg, "status"); + if (ret == 1) { + char *status; + int r = sd_bus_message_read(msg, "s", &status); + if (r < 0) { + wlr_log(WLR_ERROR, "%s new status error: %s", sni->watcher_id, strerror(-ret)); + ret = r; + } else { + free(sni->status); + sni->status = strdup(status); + wlr_log(WLR_DEBUG, "%s has new status = '%s'", sni->watcher_id, status); + set_sni_dirty(sni); + } } else { - struct swaybar_sni *sni = data; - free(sni->status); - sni->status = strdup(status); - wlr_log(WLR_DEBUG, "%s has new Status '%s'", sni->watcher_id, status); - set_sni_dirty(sni); + sni_get_property_async(sni, "Status", "s", &sni->status); } + return ret; } -static void sni_match_signal(struct swaybar_sni *sni, char *signal, - sd_bus_message_handler_t callback) { - int ret = sd_bus_match_signal(sni->tray->bus, NULL, sni->service, sni->path, +static void sni_match_signal(struct swaybar_sni *sni, sd_bus_slot **slot, + char *signal, sd_bus_message_handler_t callback) { + int ret = sd_bus_match_signal(sni->tray->bus, slot, sni->service, sni->path, sni->interface, signal, callback, sni); if (ret < 0) { - wlr_log(WLR_DEBUG, "Failed to subscribe to signal %s: %s", signal, + wlr_log(WLR_ERROR, "Failed to subscribe to signal %s: %s", signal, strerror(-ret)); } } @@ -241,9 +272,10 @@ struct swaybar_sni *create_sni(char *id, struct swaybar_tray *tray) { sni_get_property_async(sni, "ItemIsMenu", "b", &sni->item_is_menu); sni_get_property_async(sni, "Menu", "o", &sni->menu); - sni_match_signal(sni, "NewIcon", handle_new_icon); - sni_match_signal(sni, "NewAttentionIcon", handle_new_attention_icon); - sni_match_signal(sni, "NewStatus", handle_new_status); + sni_match_signal(sni, &sni->new_icon_slot, "NewIcon", handle_new_icon); + sni_match_signal(sni, &sni->new_attention_icon_slot, "NewAttentionIcon", + handle_new_attention_icon); + sni_match_signal(sni, &sni->new_status_slot, "NewStatus", handle_new_status); return sni; } @@ -253,6 +285,10 @@ void destroy_sni(struct swaybar_sni *sni) { return; } + sd_bus_slot_unref(sni->new_icon_slot); + sd_bus_slot_unref(sni->new_attention_icon_slot); + sd_bus_slot_unref(sni->new_status_slot); + free(sni->watcher_id); free(sni->service); free(sni->path); @@ -294,18 +330,11 @@ static void handle_click(struct swaybar_sni *sni, int x, int y, char *orientation = (dir = 'U' || dir == 'D') ? "vertical" : "horizontal"; int sign = (dir == 'U' || dir == 'L') ? -1 : 1; - int ret = sd_bus_call_method_async(sni->tray->bus, NULL, sni->service, - sni->path, sni->interface, "Scroll", NULL, NULL, "is", - delta*sign, orientation); - if (ret < 0) { - wlr_log(WLR_DEBUG, "Failed to scroll on SNI: %s", strerror(-ret)); - } + sd_bus_call_method_async(sni->tray->bus, NULL, sni->service, sni->path, + sni->interface, "Scroll", NULL, NULL, "is", delta*sign, orientation); } else { - int ret = sd_bus_call_method_async(sni->tray->bus, NULL, sni->service, - sni->path, sni->interface, method, NULL, NULL, "ii", x, y); - if (ret < 0) { - wlr_log(WLR_DEBUG, "Failed to click on SNI: %s", strerror(-ret)); - } + sd_bus_call_method_async(sni->tray->bus, NULL, sni->service, sni->path, + sni->interface, method, NULL, NULL, "ii", x, y); } } @@ -317,7 +346,7 @@ static int cmp_sni_id(const void *item, const void *cmp_to) { static enum hotspot_event_handling icon_hotspot_callback( struct swaybar_output *output, struct swaybar_hotspot *hotspot, int x, int y, enum x11_button button, void *data) { - wlr_log(WLR_DEBUG, "Clicked on Status Notifier Item '%s'", (char *)data); + wlr_log(WLR_DEBUG, "Clicked on %s", (char *)data); struct swaybar_tray *tray = output->bar->tray; int idx = list_seq_find(tray->items, cmp_sni_id, data); @@ -331,7 +360,7 @@ static enum hotspot_event_handling icon_hotspot_callback( int global_y = output->output_y + (top_bar ? config->gaps.top + y: (int) output->output_height - config->gaps.bottom - y); - wlr_log(WLR_DEBUG, "Guessing click at (%d, %d)", global_x, global_y); + wlr_log(WLR_DEBUG, "Guessing click position at (%d, %d)", global_x, global_y); handle_click(sni, global_x, global_y, button, 1); // TODO get delta from event return HOTSPOT_IGNORE; } else { @@ -396,7 +425,7 @@ uint32_t render_sni(cairo_t *cairo, struct swaybar_output *output, double *x, icon_size = actual_size < ideal_size ? actual_size*(ideal_size/actual_size) : ideal_size; icon = cairo_image_surface_scale(sni->icon, icon_size, icon_size); - } else { // draw a sad face + } else { // draw a :( icon_size = ideal_size*0.8; icon = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, icon_size, icon_size); cairo_t *cairo_icon = cairo_create(icon); diff --git a/swaybar/tray/tray.c b/swaybar/tray/tray.c index acc300af..0c3517cb 100644 --- a/swaybar/tray/tray.c +++ b/swaybar/tray/tray.c @@ -79,7 +79,7 @@ void destroy_tray(struct swaybar_tray *tray) { finish_host(&tray->host_xdg); finish_host(&tray->host_kde); for (int i = 0; i < tray->items->length; ++i) { - destroy_sni(tray->items->items[0]); + destroy_sni(tray->items->items[i]); } list_free(tray->items); destroy_watcher(tray->watcher_xdg);