i3bar: count references to blocks
This prevents blocks from being destroyed before their hotspots are destroyed, in case it is used for a pending click event that fires between the bar receiving a new status, which destroys the block, and the bar rendering the new status, which destroys the hotspot; this problem can be easily produced by scrolling on a block that immediately causes a new status to be sent, with multiple outputs
This commit is contained in:
parent
af9e8f94cc
commit
2eaef80206
|
@ -36,6 +36,7 @@ struct i3bar_protocol_state {
|
||||||
|
|
||||||
struct i3bar_block {
|
struct i3bar_block {
|
||||||
struct wl_list link;
|
struct wl_list link;
|
||||||
|
int ref_count;
|
||||||
char *full_text, *short_text, *align;
|
char *full_text, *short_text, *align;
|
||||||
bool urgent;
|
bool urgent;
|
||||||
uint32_t *color;
|
uint32_t *color;
|
||||||
|
@ -73,7 +74,7 @@ void status_line_free(struct status_line *status);
|
||||||
bool i3bar_handle_readable(struct status_line *status);
|
bool i3bar_handle_readable(struct status_line *status);
|
||||||
enum hotspot_event_handling i3bar_block_send_click(struct status_line *status,
|
enum hotspot_event_handling i3bar_block_send_click(struct status_line *status,
|
||||||
struct i3bar_block *block, int x, int y, enum x11_button button);
|
struct i3bar_block *block, int x, int y, enum x11_button button);
|
||||||
void i3bar_block_free(struct i3bar_block *block);
|
void i3bar_block_unref(struct i3bar_block *block);
|
||||||
enum x11_button wl_button_to_x11_button(uint32_t button);
|
enum x11_button wl_button_to_x11_button(uint32_t button);
|
||||||
enum x11_button wl_axis_to_x11_button(uint32_t axis, wl_fixed_t value);
|
enum x11_button wl_axis_to_x11_button(uint32_t axis, wl_fixed_t value);
|
||||||
|
|
||||||
|
|
|
@ -8,11 +8,10 @@
|
||||||
#include "swaybar/config.h"
|
#include "swaybar/config.h"
|
||||||
#include "swaybar/status_line.h"
|
#include "swaybar/status_line.h"
|
||||||
|
|
||||||
void i3bar_block_free(struct i3bar_block *block) {
|
static void i3bar_block_free(struct i3bar_block *block) {
|
||||||
if (!block) {
|
if (!block) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
wl_list_remove(&block->link);
|
|
||||||
free(block->full_text);
|
free(block->full_text);
|
||||||
free(block->short_text);
|
free(block->short_text);
|
||||||
free(block->align);
|
free(block->align);
|
||||||
|
@ -22,10 +21,17 @@ void i3bar_block_free(struct i3bar_block *block) {
|
||||||
free(block);
|
free(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void i3bar_block_unref(struct i3bar_block *block) {
|
||||||
|
if (--block->ref_count == 0) {
|
||||||
|
i3bar_block_free(block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static bool i3bar_parse_json(struct status_line *status, const char *text) {
|
static bool i3bar_parse_json(struct status_line *status, const char *text) {
|
||||||
struct i3bar_block *block, *tmp;
|
struct i3bar_block *block, *tmp;
|
||||||
wl_list_for_each_safe(block, tmp, &status->blocks, link) {
|
wl_list_for_each_safe(block, tmp, &status->blocks, link) {
|
||||||
i3bar_block_free(block);
|
wl_list_remove(&block->link);
|
||||||
|
i3bar_block_unref(block);
|
||||||
}
|
}
|
||||||
json_object *results = json_tokener_parse(text);
|
json_object *results = json_tokener_parse(text);
|
||||||
if (!results) {
|
if (!results) {
|
||||||
|
@ -61,6 +67,7 @@ static bool i3bar_parse_json(struct status_line *status, const char *text) {
|
||||||
json_object_object_get_ex(json, "border_right", &border_right);
|
json_object_object_get_ex(json, "border_right", &border_right);
|
||||||
|
|
||||||
struct i3bar_block *block = calloc(1, sizeof(struct i3bar_block));
|
struct i3bar_block *block = calloc(1, sizeof(struct i3bar_block));
|
||||||
|
block->ref_count = 1;
|
||||||
block->full_text = full_text ?
|
block->full_text = full_text ?
|
||||||
strdup(json_object_get_string(full_text)) : NULL;
|
strdup(json_object_get_string(full_text)) : NULL;
|
||||||
block->short_text = short_text ?
|
block->short_text = short_text ?
|
||||||
|
|
|
@ -115,6 +115,10 @@ static enum hotspot_event_handling block_hotspot_callback(struct swaybar_output
|
||||||
return i3bar_block_send_click(status, block, x, y, button);
|
return i3bar_block_send_click(status, block, x, y, button);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void i3bar_block_unref_callback(void *data) {
|
||||||
|
i3bar_block_unref(data);
|
||||||
|
}
|
||||||
|
|
||||||
static uint32_t render_status_block(cairo_t *cairo,
|
static uint32_t render_status_block(cairo_t *cairo,
|
||||||
struct swaybar_config *config, struct swaybar_output *output,
|
struct swaybar_config *config, struct swaybar_output *output,
|
||||||
struct i3bar_block *block, double *x,
|
struct i3bar_block *block, double *x,
|
||||||
|
@ -179,8 +183,9 @@ static uint32_t render_status_block(cairo_t *cairo,
|
||||||
hotspot->width = width;
|
hotspot->width = width;
|
||||||
hotspot->height = height;
|
hotspot->height = height;
|
||||||
hotspot->callback = block_hotspot_callback;
|
hotspot->callback = block_hotspot_callback;
|
||||||
hotspot->destroy = NULL;
|
hotspot->destroy = i3bar_block_unref_callback;
|
||||||
hotspot->data = block;
|
hotspot->data = block;
|
||||||
|
block->ref_count++;
|
||||||
wl_list_insert(&output->hotspots, &hotspot->link);
|
wl_list_insert(&output->hotspots, &hotspot->link);
|
||||||
|
|
||||||
double pos = *x;
|
double pos = *x;
|
||||||
|
|
|
@ -130,7 +130,7 @@ void status_line_free(struct status_line *status) {
|
||||||
case PROTOCOL_I3BAR:;
|
case PROTOCOL_I3BAR:;
|
||||||
struct i3bar_block *block, *tmp;
|
struct i3bar_block *block, *tmp;
|
||||||
wl_list_for_each_safe(block, tmp, &status->blocks, link) {
|
wl_list_for_each_safe(block, tmp, &status->blocks, link) {
|
||||||
i3bar_block_free(block);
|
i3bar_block_unref(block);
|
||||||
}
|
}
|
||||||
free(status->i3bar_state.buffer);
|
free(status->i3bar_state.buffer);
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in a new issue