aboutsummaryrefslogtreecommitdiffstats
path: root/swaybar
diff options
context:
space:
mode:
authorLibravatar Ian Fan <ianfan0@gmail.com>2019-01-04 11:57:18 +0000
committerLibravatar Ian Fan <ianfan0@gmail.com>2019-01-08 12:18:59 +0000
commitd093c3ac55649e9a30504cfeaff506329ffd6ec7 (patch)
tree6ce91378ead75a72910744a1e694d33accc6215d /swaybar
parentswaybar: free the right item during tray destruction (diff)
downloadsway-d093c3ac55649e9a30504cfeaff506329ffd6ec7.tar.gz
sway-d093c3ac55649e9a30504cfeaff506329ffd6ec7.tar.zst
sway-d093c3ac55649e9a30504cfeaff506329ffd6ec7.zip
swaybar: handle SNI signals better
This fixes a crash caused by callbacks not matching the right sender, and frees old values later, before they are re-assigned.
Diffstat (limited to 'swaybar')
-rw-r--r--swaybar/tray/item.c94
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 */
178static 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
159static int handle_new_icon(sd_bus_message *msg, void *data, sd_bus_error *error) { 191static 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
174static int handle_new_attention_icon(sd_bus_message *msg, void *data, 198static 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
190static int handle_new_status(sd_bus_message *msg, void *data, sd_bus_error *error) { 206static 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
205static void sni_match_signal(struct swaybar_sni *sni, char *signal, 228static 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);