diff options
Diffstat (limited to 'swaybar')
-rw-r--r-- | swaybar/tray/item.c | 94 |
1 files changed, 61 insertions, 33 deletions
diff --git a/swaybar/tray/item.c b/swaybar/tray/item.c index 130496ec..44fd876c 100644 --- a/swaybar/tray/item.c +++ b/swaybar/tray/item.c | |||
@@ -78,6 +78,7 @@ static int read_pixmap(sd_bus_message *msg, struct swaybar_sni *sni, | |||
78 | 78 | ||
79 | sd_bus_message_exit_container(msg); | 79 | sd_bus_message_exit_container(msg); |
80 | } | 80 | } |
81 | list_free_items_and_destroy(*dest); | ||
81 | *dest = pixmaps; | 82 | *dest = pixmaps; |
82 | 83 | ||
83 | return ret; | 84 | return ret; |
@@ -121,6 +122,10 @@ static int get_property_callback(sd_bus_message *msg, void *data, | |||
121 | goto cleanup; | 122 | goto cleanup; |
122 | } | 123 | } |
123 | } else { | 124 | } else { |
125 | if (*type == 's' || *type == 'o') { | ||
126 | free(*(char **)dest); | ||
127 | } | ||
128 | |||
124 | ret = sd_bus_message_read(msg, type, dest); | 129 | ret = sd_bus_message_read(msg, type, dest); |
125 | if (ret < 0) { | 130 | if (ret < 0) { |
126 | wlr_log(WLR_DEBUG, "Failed to read property %s: %s", prop, | 131 | wlr_log(WLR_DEBUG, "Failed to read property %s: %s", prop, |
@@ -156,55 +161,73 @@ static void sni_get_property_async(struct swaybar_sni *sni, const char *prop, | |||
156 | } | 161 | } |
157 | } | 162 | } |
158 | 163 | ||
164 | /* | ||
165 | * There is a quirk in sd-bus that in some systems, it is unable to get the | ||
166 | * well-known names on the bus, so it cannot identify if an incoming signal, | ||
167 | * which uses the sender's unique name, actually matches the callback's matching | ||
168 | * sender if the callback uses a well-known name, in which case it just calls | ||
169 | * the callback and hopes for the best, resulting in false positives. In the | ||
170 | * case of NewIcon & NewAttentionIcon, this doesn't affect anything, but it | ||
171 | * means that for NewStatus, if the SNI does not definitely match the sender, | ||
172 | * then the safe thing to do is to query the status independently. | ||
173 | * This function returns 1 if the SNI definitely matches the signal sender, | ||
174 | * which is returned by the calling function to indicate that signal matching | ||
175 | * can stop since it has already found the required callback, otherwise, it | ||
176 | * returns 0, which allows matching to continue. | ||
177 | */ | ||
178 | static int sni_check_msg_sender(struct swaybar_sni *sni, sd_bus_message *msg, | ||
179 | const char *signal) { | ||
180 | bool has_well_known_names = | ||
181 | sd_bus_creds_get_mask(sd_bus_message_get_creds(msg)) & SD_BUS_CREDS_WELL_KNOWN_NAMES; | ||
182 | if (sni->service[0] == ':' || has_well_known_names) { | ||
183 | wlr_log(WLR_DEBUG, "%s has new %s", sni->watcher_id, signal); | ||
184 | return 1; | ||
185 | } else { | ||
186 | wlr_log(WLR_DEBUG, "%s may have new %s", sni->watcher_id, signal); | ||
187 | return 0; | ||
188 | } | ||
189 | } | ||
190 | |||
159 | static int handle_new_icon(sd_bus_message *msg, void *data, sd_bus_error *error) { | 191 | static int handle_new_icon(sd_bus_message *msg, void *data, sd_bus_error *error) { |
160 | struct swaybar_sni *sni = data; | 192 | struct swaybar_sni *sni = data; |
161 | wlr_log(WLR_DEBUG, "%s has new IconName", sni->watcher_id); | ||
162 | |||
163 | free(sni->icon_name); | ||
164 | sni->icon_name = NULL; | ||
165 | sni_get_property_async(sni, "IconName", "s", &sni->icon_name); | 193 | sni_get_property_async(sni, "IconName", "s", &sni->icon_name); |
166 | |||
167 | list_free_items_and_destroy(sni->icon_pixmap); | ||
168 | sni->icon_pixmap = NULL; | ||
169 | sni_get_property_async(sni, "IconPixmap", NULL, &sni->icon_pixmap); | 194 | sni_get_property_async(sni, "IconPixmap", NULL, &sni->icon_pixmap); |
170 | 195 | return sni_check_msg_sender(sni, msg, "icon"); | |
171 | return 0; | ||
172 | } | 196 | } |
173 | 197 | ||
174 | static int handle_new_attention_icon(sd_bus_message *msg, void *data, | 198 | static int handle_new_attention_icon(sd_bus_message *msg, void *data, |
175 | sd_bus_error *error) { | 199 | sd_bus_error *error) { |
176 | struct swaybar_sni *sni = data; | 200 | struct swaybar_sni *sni = data; |
177 | wlr_log(WLR_DEBUG, "%s has new AttentionIconName", sni->watcher_id); | ||
178 | |||
179 | free(sni->attention_icon_name); | ||
180 | sni->attention_icon_name = NULL; | ||
181 | sni_get_property_async(sni, "AttentionIconName", "s", &sni->attention_icon_name); | 201 | sni_get_property_async(sni, "AttentionIconName", "s", &sni->attention_icon_name); |
182 | |||
183 | list_free_items_and_destroy(sni->attention_icon_pixmap); | ||
184 | sni->attention_icon_pixmap = NULL; | ||
185 | sni_get_property_async(sni, "AttentionIconPixmap", NULL, &sni->attention_icon_pixmap); | 202 | sni_get_property_async(sni, "AttentionIconPixmap", NULL, &sni->attention_icon_pixmap); |
186 | 203 | return sni_check_msg_sender(sni, msg, "attention icon"); | |
187 | return 0; | ||
188 | } | 204 | } |
189 | 205 | ||
190 | static int handle_new_status(sd_bus_message *msg, void *data, sd_bus_error *error) { | 206 | static int handle_new_status(sd_bus_message *msg, void *data, sd_bus_error *error) { |
191 | char *status; | 207 | struct swaybar_sni *sni = data; |
192 | int ret = sd_bus_message_read(msg, "s", &status); | 208 | int ret = sni_check_msg_sender(sni, msg, "status"); |
193 | if (ret < 0) { | 209 | if (ret == 1) { |
194 | wlr_log(WLR_DEBUG, "Failed to read new status message: %s", strerror(-ret)); | 210 | char *status; |
211 | int r = sd_bus_message_read(msg, "s", &status); | ||
212 | if (r < 0) { | ||
213 | wlr_log(WLR_ERROR, "Failed to read new status message: %s", strerror(-ret)); | ||
214 | ret = r; | ||
215 | } else { | ||
216 | free(sni->status); | ||
217 | sni->status = strdup(status); | ||
218 | wlr_log(WLR_DEBUG, "%s has new status: %s", sni->watcher_id, status); | ||
219 | set_sni_dirty(sni); | ||
220 | } | ||
195 | } else { | 221 | } else { |
196 | struct swaybar_sni *sni = data; | 222 | sni_get_property_async(sni, "Status", "s", &sni->status); |
197 | free(sni->status); | ||
198 | sni->status = strdup(status); | ||
199 | wlr_log(WLR_DEBUG, "%s has new Status '%s'", sni->watcher_id, status); | ||
200 | set_sni_dirty(sni); | ||
201 | } | 223 | } |
224 | |||
202 | return ret; | 225 | return ret; |
203 | } | 226 | } |
204 | 227 | ||
205 | static void sni_match_signal(struct swaybar_sni *sni, char *signal, | 228 | static void sni_match_signal(struct swaybar_sni *sni, sd_bus_slot **slot, |
206 | sd_bus_message_handler_t callback) { | 229 | char *signal, sd_bus_message_handler_t callback) { |
207 | int ret = sd_bus_match_signal(sni->tray->bus, NULL, sni->service, sni->path, | 230 | int ret = sd_bus_match_signal(sni->tray->bus, slot, sni->service, sni->path, |
208 | sni->interface, signal, callback, sni); | 231 | sni->interface, signal, callback, sni); |
209 | if (ret < 0) { | 232 | if (ret < 0) { |
210 | wlr_log(WLR_DEBUG, "Failed to subscribe to signal %s: %s", signal, | 233 | wlr_log(WLR_DEBUG, "Failed to subscribe to signal %s: %s", signal, |
@@ -241,9 +264,10 @@ struct swaybar_sni *create_sni(char *id, struct swaybar_tray *tray) { | |||
241 | sni_get_property_async(sni, "ItemIsMenu", "b", &sni->item_is_menu); | 264 | sni_get_property_async(sni, "ItemIsMenu", "b", &sni->item_is_menu); |
242 | sni_get_property_async(sni, "Menu", "o", &sni->menu); | 265 | sni_get_property_async(sni, "Menu", "o", &sni->menu); |
243 | 266 | ||
244 | sni_match_signal(sni, "NewIcon", handle_new_icon); | 267 | sni_match_signal(sni, &sni->new_icon_slot, "NewIcon", handle_new_icon); |
245 | sni_match_signal(sni, "NewAttentionIcon", handle_new_attention_icon); | 268 | sni_match_signal(sni, &sni->new_attention_icon_slot, "NewAttentionIcon", |
246 | sni_match_signal(sni, "NewStatus", handle_new_status); | 269 | handle_new_attention_icon); |
270 | sni_match_signal(sni, &sni->new_status_slot, "NewStatus", handle_new_status); | ||
247 | 271 | ||
248 | return sni; | 272 | return sni; |
249 | } | 273 | } |
@@ -253,6 +277,10 @@ void destroy_sni(struct swaybar_sni *sni) { | |||
253 | return; | 277 | return; |
254 | } | 278 | } |
255 | 279 | ||
280 | sd_bus_slot_unref(sni->new_icon_slot); | ||
281 | sd_bus_slot_unref(sni->new_attention_icon_slot); | ||
282 | sd_bus_slot_unref(sni->new_status_slot); | ||
283 | |||
256 | free(sni->watcher_id); | 284 | free(sni->watcher_id); |
257 | free(sni->service); | 285 | free(sni->service); |
258 | free(sni->path); | 286 | free(sni->path); |