2018-03-29 04:07:35 +00:00
|
|
|
#include <limits.h>
|
2019-09-03 01:41:11 +00:00
|
|
|
#include <poll.h>
|
2019-01-22 10:43:48 +00:00
|
|
|
#include <stdio.h>
|
2018-03-29 03:56:02 +00:00
|
|
|
#include <string.h>
|
|
|
|
#include <strings.h>
|
2019-01-23 18:00:14 +00:00
|
|
|
#include <json.h>
|
2018-03-29 03:56:02 +00:00
|
|
|
#include "swaybar/config.h"
|
|
|
|
#include "swaybar/ipc.h"
|
2019-09-03 01:41:11 +00:00
|
|
|
#include "swaybar/status_line.h"
|
|
|
|
#if HAVE_TRAY
|
|
|
|
#include "swaybar/tray/tray.h"
|
|
|
|
#endif
|
2018-12-09 15:10:41 +00:00
|
|
|
#include "config.h"
|
2018-03-29 03:56:02 +00:00
|
|
|
#include "ipc-client.h"
|
2018-10-08 15:40:13 +00:00
|
|
|
#include "list.h"
|
2019-01-20 18:51:12 +00:00
|
|
|
#include "log.h"
|
2019-09-03 01:41:11 +00:00
|
|
|
#include "loop.h"
|
2019-01-22 10:43:48 +00:00
|
|
|
#include "util.h"
|
2018-03-29 03:56:02 +00:00
|
|
|
|
2018-03-31 02:02:55 +00:00
|
|
|
void ipc_send_workspace_command(struct swaybar *bar, const char *ws) {
|
2019-01-22 11:43:37 +00:00
|
|
|
uint32_t size = strlen("workspace \"\"") + strlen(ws);
|
|
|
|
for (size_t i = 0; i < strlen(ws); ++i) {
|
|
|
|
if (ws[i] == '"' || ws[i] == '\\') {
|
|
|
|
++size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-22 19:00:33 +00:00
|
|
|
char *command = malloc(size + 1);
|
2019-01-22 11:43:37 +00:00
|
|
|
if (!command) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
strcpy(command, "workspace \"");
|
|
|
|
strcpy(&command[size - 1], "\"");
|
|
|
|
for (size_t i = 0, d = strlen("workspace \""); i < strlen(ws); ++i) {
|
|
|
|
if (ws[i] == '"' || ws[i] == '\\') {
|
|
|
|
command[d++] = '\\';
|
|
|
|
}
|
|
|
|
command[d++] = ws[i];
|
|
|
|
}
|
|
|
|
|
2020-03-05 16:28:43 +00:00
|
|
|
free(ipc_single_command(bar->ipc_socketfd, IPC_COMMAND, command, &size));
|
2019-01-16 01:57:53 +00:00
|
|
|
free(command);
|
2018-03-31 02:02:55 +00:00
|
|
|
}
|
|
|
|
|
2018-03-29 03:56:02 +00:00
|
|
|
char *parse_font(const char *font) {
|
|
|
|
char *new_font = NULL;
|
|
|
|
if (strncmp("pango:", font, 6) == 0) {
|
|
|
|
font += 6;
|
|
|
|
}
|
|
|
|
new_font = strdup(font);
|
|
|
|
return new_font;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ipc_parse_colors(
|
|
|
|
struct swaybar_config *config, json_object *colors) {
|
2019-12-28 04:33:55 +00:00
|
|
|
struct {
|
|
|
|
const char *name;
|
|
|
|
uint32_t *color;
|
|
|
|
} properties[] = {
|
|
|
|
{ "background", &config->colors.background },
|
|
|
|
{ "statusline", &config->colors.statusline },
|
|
|
|
{ "separator", &config->colors.separator },
|
|
|
|
{ "focused_background", &config->colors.focused_background },
|
|
|
|
{ "focused_statusline", &config->colors.focused_statusline },
|
|
|
|
{ "focused_separator", &config->colors.focused_separator },
|
|
|
|
{ "focused_workspace_border", &config->colors.focused_workspace.border },
|
|
|
|
{ "focused_workspace_bg", &config->colors.focused_workspace.background },
|
|
|
|
{ "focused_workspace_text", &config->colors.focused_workspace.text },
|
|
|
|
{ "active_workspace_border", &config->colors.active_workspace.border },
|
|
|
|
{ "active_workspace_bg", &config->colors.active_workspace.background },
|
|
|
|
{ "active_workspace_text", &config->colors.active_workspace.text },
|
|
|
|
{ "inactive_workspace_border", &config->colors.inactive_workspace.border },
|
|
|
|
{ "inactive_workspace_bg", &config->colors.inactive_workspace.background },
|
|
|
|
{ "inactive_workspace_text", &config->colors.inactive_workspace.text },
|
|
|
|
{ "urgent_workspace_border", &config->colors.urgent_workspace.border },
|
|
|
|
{ "urgent_workspace_bg", &config->colors.urgent_workspace.background },
|
|
|
|
{ "urgent_workspace_text", &config->colors.urgent_workspace.text },
|
|
|
|
{ "binding_mode_border", &config->colors.binding_mode.border },
|
|
|
|
{ "binding_mode_bg", &config->colors.binding_mode.background },
|
|
|
|
{ "binding_mode_text", &config->colors.binding_mode.text },
|
|
|
|
};
|
|
|
|
|
|
|
|
for (size_t i = 0; i < sizeof(properties) / sizeof(properties[i]); i++) {
|
|
|
|
json_object *object;
|
|
|
|
if (json_object_object_get_ex(colors, properties[i].name, &object)) {
|
|
|
|
const char *hexstring = json_object_get_string(object);
|
|
|
|
if (!parse_color(hexstring, properties[i].color)) {
|
|
|
|
sway_log(SWAY_ERROR, "Ignoring invalid %s: %s",
|
|
|
|
properties[i].name, hexstring);
|
|
|
|
}
|
|
|
|
}
|
2018-03-29 03:56:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-24 17:42:25 +00:00
|
|
|
static bool ipc_parse_config(
|
2018-03-29 03:56:02 +00:00
|
|
|
struct swaybar_config *config, const char *payload) {
|
|
|
|
json_object *bar_config = json_tokener_parse(payload);
|
2018-09-24 17:42:25 +00:00
|
|
|
json_object *success;
|
|
|
|
if (json_object_object_get_ex(bar_config, "success", &success)
|
|
|
|
&& !json_object_get_boolean(success)) {
|
2019-09-03 01:41:11 +00:00
|
|
|
sway_log(SWAY_ERROR, "No bar with that ID. Use 'swaymsg -t "
|
|
|
|
"get_bar_config' to get the available bar configs.");
|
2018-09-24 17:42:25 +00:00
|
|
|
json_object_put(bar_config);
|
|
|
|
return false;
|
|
|
|
}
|
2019-09-03 01:41:11 +00:00
|
|
|
|
|
|
|
json_object *bar_height = json_object_object_get(bar_config, "bar_height");
|
|
|
|
if (bar_height) {
|
|
|
|
config->height = json_object_get_int(bar_height);
|
2018-11-17 16:11:28 +00:00
|
|
|
}
|
2019-09-03 01:41:11 +00:00
|
|
|
|
|
|
|
json_object *binding_mode_indicator =
|
|
|
|
json_object_object_get(bar_config, "binding_mode_indicator");
|
2018-03-29 03:56:02 +00:00
|
|
|
if (binding_mode_indicator) {
|
2019-09-03 01:41:11 +00:00
|
|
|
config->binding_mode_indicator =
|
|
|
|
json_object_get_boolean(binding_mode_indicator);
|
2018-03-29 03:56:02 +00:00
|
|
|
}
|
2019-09-03 01:41:11 +00:00
|
|
|
|
|
|
|
json_object *bindings = json_object_object_get(bar_config, "bindings");
|
|
|
|
while (config->bindings->length) {
|
|
|
|
struct swaybar_binding *binding = config->bindings->items[0];
|
|
|
|
list_del(config->bindings, 0);
|
|
|
|
free_binding(binding);
|
2018-03-29 03:56:02 +00:00
|
|
|
}
|
2019-09-03 01:41:11 +00:00
|
|
|
if (bindings) {
|
|
|
|
int length = json_object_array_length(bindings);
|
|
|
|
for (int i = 0; i < length; ++i) {
|
|
|
|
json_object *bindobj = json_object_array_get_idx(bindings, i);
|
|
|
|
struct swaybar_binding *binding =
|
|
|
|
calloc(1, sizeof(struct swaybar_binding));
|
|
|
|
binding->button = json_object_get_int(
|
|
|
|
json_object_object_get(bindobj, "event_code"));
|
|
|
|
binding->command = strdup(json_object_get_string(
|
|
|
|
json_object_object_get(bindobj, "command")));
|
|
|
|
binding->release = json_object_get_boolean(
|
|
|
|
json_object_object_get(bindobj, "release"));
|
|
|
|
list_add(config->bindings, binding);
|
|
|
|
}
|
2018-03-29 03:56:02 +00:00
|
|
|
}
|
2019-09-03 01:41:11 +00:00
|
|
|
|
|
|
|
json_object *colors = json_object_object_get(bar_config, "colors");
|
|
|
|
if (colors) {
|
|
|
|
ipc_parse_colors(config, colors);
|
2019-01-11 04:43:45 +00:00
|
|
|
}
|
2019-09-03 01:41:11 +00:00
|
|
|
|
|
|
|
json_object *font = json_object_object_get(bar_config, "font");
|
|
|
|
if (font) {
|
2022-07-01 10:23:04 +00:00
|
|
|
pango_font_description_free(config->font_description);
|
|
|
|
char *font_value = parse_font(json_object_get_string(font));
|
|
|
|
config->font_description = pango_font_description_from_string(font_value);
|
|
|
|
free(font_value);
|
2019-01-11 05:12:24 +00:00
|
|
|
}
|
2019-09-03 01:41:11 +00:00
|
|
|
|
|
|
|
json_object *gaps = json_object_object_get(bar_config, "gaps");
|
2018-11-28 16:23:48 +00:00
|
|
|
if (gaps) {
|
|
|
|
json_object *top = json_object_object_get(gaps, "top");
|
|
|
|
if (top) {
|
|
|
|
config->gaps.top = json_object_get_int(top);
|
|
|
|
}
|
|
|
|
json_object *right = json_object_object_get(gaps, "right");
|
|
|
|
if (right) {
|
|
|
|
config->gaps.right = json_object_get_int(right);
|
|
|
|
}
|
|
|
|
json_object *bottom = json_object_object_get(gaps, "bottom");
|
|
|
|
if (bottom) {
|
|
|
|
config->gaps.bottom = json_object_get_int(bottom);
|
|
|
|
}
|
|
|
|
json_object *left = json_object_object_get(gaps, "left");
|
|
|
|
if (left) {
|
|
|
|
config->gaps.left = json_object_get_int(left);
|
|
|
|
}
|
|
|
|
}
|
2019-09-03 01:41:11 +00:00
|
|
|
|
|
|
|
json_object *hidden_state =
|
|
|
|
json_object_object_get(bar_config, "hidden_state");
|
2018-10-12 19:32:48 +00:00
|
|
|
if (hidden_state) {
|
|
|
|
free(config->hidden_state);
|
|
|
|
config->hidden_state = strdup(json_object_get_string(hidden_state));
|
|
|
|
}
|
2019-09-03 01:41:11 +00:00
|
|
|
|
|
|
|
json_object *mode = json_object_object_get(bar_config, "mode");
|
2018-10-12 19:32:48 +00:00
|
|
|
if (mode) {
|
|
|
|
free(config->mode);
|
|
|
|
config->mode = strdup(json_object_get_string(mode));
|
|
|
|
}
|
2018-03-29 03:56:02 +00:00
|
|
|
|
2019-09-03 01:41:11 +00:00
|
|
|
json_object *outputs = json_object_object_get(bar_config, "outputs");
|
2018-03-29 03:56:02 +00:00
|
|
|
struct config_output *output, *tmp;
|
|
|
|
wl_list_for_each_safe(output, tmp, &config->outputs, link) {
|
|
|
|
wl_list_remove(&output->link);
|
|
|
|
free(output->name);
|
|
|
|
free(output);
|
|
|
|
}
|
|
|
|
if (outputs) {
|
|
|
|
int length = json_object_array_length(outputs);
|
|
|
|
for (int i = 0; i < length; ++i) {
|
|
|
|
json_object *output = json_object_array_get_idx(outputs, i);
|
|
|
|
const char *name = json_object_get_string(output);
|
|
|
|
if (strcmp("*", name) == 0) {
|
2019-09-03 01:41:11 +00:00
|
|
|
struct config_output *coutput, *tmp;
|
|
|
|
wl_list_for_each_safe(coutput, tmp, &config->outputs, link) {
|
|
|
|
wl_list_remove(&coutput->link);
|
|
|
|
free(coutput->name);
|
|
|
|
free(coutput);
|
|
|
|
}
|
2018-03-29 03:56:02 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
struct config_output *coutput = calloc(
|
|
|
|
1, sizeof(struct config_output));
|
|
|
|
coutput->name = strdup(name);
|
|
|
|
wl_list_insert(&config->outputs, &coutput->link);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-03 01:41:11 +00:00
|
|
|
json_object *pango_markup =
|
|
|
|
json_object_object_get(bar_config, "pango_markup");
|
|
|
|
if (pango_markup) {
|
|
|
|
config->pango_markup = json_object_get_boolean(pango_markup);
|
|
|
|
}
|
|
|
|
|
|
|
|
json_object *position = json_object_object_get(bar_config, "position");
|
|
|
|
if (position) {
|
|
|
|
config->position = parse_position(json_object_get_string(position));
|
|
|
|
}
|
|
|
|
|
|
|
|
json_object *separator_symbol =
|
|
|
|
json_object_object_get(bar_config, "separator_symbol");
|
|
|
|
if (separator_symbol) {
|
|
|
|
free(config->sep_symbol);
|
|
|
|
config->sep_symbol = strdup(json_object_get_string(separator_symbol));
|
|
|
|
}
|
|
|
|
|
|
|
|
json_object *status_command =
|
|
|
|
json_object_object_get(bar_config, "status_command");
|
|
|
|
if (status_command) {
|
|
|
|
const char *command = json_object_get_string(status_command);
|
|
|
|
free(config->status_command);
|
|
|
|
config->status_command = strdup(command);
|
|
|
|
}
|
|
|
|
|
|
|
|
json_object *status_edge_padding =
|
|
|
|
json_object_object_get(bar_config, "status_edge_padding");
|
|
|
|
if (status_edge_padding) {
|
|
|
|
config->status_edge_padding = json_object_get_int(status_edge_padding);
|
|
|
|
}
|
|
|
|
|
|
|
|
json_object *status_padding =
|
|
|
|
json_object_object_get(bar_config, "status_padding");
|
|
|
|
if (status_padding) {
|
|
|
|
config->status_padding = json_object_get_int(status_padding);
|
|
|
|
}
|
|
|
|
|
|
|
|
json_object *strip_workspace_name =
|
|
|
|
json_object_object_get(bar_config, "strip_workspace_name");
|
|
|
|
if (strip_workspace_name) {
|
|
|
|
config->strip_workspace_name =
|
|
|
|
json_object_get_boolean(strip_workspace_name);
|
2018-03-29 03:56:02 +00:00
|
|
|
}
|
|
|
|
|
2019-09-03 01:41:11 +00:00
|
|
|
json_object *strip_workspace_numbers =
|
|
|
|
json_object_object_get(bar_config, "strip_workspace_numbers");
|
|
|
|
if (strip_workspace_numbers) {
|
|
|
|
config->strip_workspace_numbers =
|
|
|
|
json_object_get_boolean(strip_workspace_numbers);
|
|
|
|
}
|
|
|
|
|
|
|
|
json_object *workspace_buttons =
|
|
|
|
json_object_object_get(bar_config, "workspace_buttons");
|
|
|
|
if (workspace_buttons) {
|
|
|
|
config->workspace_buttons = json_object_get_boolean(workspace_buttons);
|
|
|
|
}
|
|
|
|
|
2020-10-03 13:45:26 +00:00
|
|
|
json_object *workspace_min_width =
|
|
|
|
json_object_object_get(bar_config, "workspace_min_width");
|
|
|
|
if (workspace_min_width) {
|
|
|
|
config->workspace_min_width = json_object_get_int(workspace_min_width);
|
|
|
|
}
|
|
|
|
|
2019-09-03 01:41:11 +00:00
|
|
|
json_object *wrap_scroll = json_object_object_get(bar_config, "wrap_scroll");
|
|
|
|
if (wrap_scroll) {
|
|
|
|
config->wrap_scroll = json_object_get_boolean(wrap_scroll);
|
|
|
|
}
|
2018-12-09 15:10:41 +00:00
|
|
|
#if HAVE_TRAY
|
|
|
|
json_object *tray_outputs, *tray_padding, *tray_bindings, *icon_theme;
|
|
|
|
|
2019-09-03 01:41:11 +00:00
|
|
|
if (config->tray_outputs && config->tray_outputs->length) {
|
|
|
|
list_free_items_and_destroy(config->tray_outputs);
|
|
|
|
}
|
2018-12-09 15:10:41 +00:00
|
|
|
if ((json_object_object_get_ex(bar_config, "tray_outputs", &tray_outputs))) {
|
|
|
|
config->tray_outputs = create_list();
|
|
|
|
int length = json_object_array_length(tray_outputs);
|
|
|
|
for (int i = 0; i < length; ++i) {
|
2019-09-03 01:41:11 +00:00
|
|
|
json_object *output= json_object_array_get_idx(tray_outputs, i);
|
|
|
|
const char *name = json_object_get_string(output);
|
|
|
|
if (strcmp(name, "none") == 0) {
|
|
|
|
config->tray_hidden = true;
|
|
|
|
list_free_items_and_destroy(config->tray_outputs);
|
|
|
|
config->tray_outputs = create_list();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
list_add(config->tray_outputs, strdup(name));
|
2018-12-09 15:10:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((json_object_object_get_ex(bar_config, "tray_padding", &tray_padding))) {
|
|
|
|
config->tray_padding = json_object_get_int(tray_padding);
|
|
|
|
}
|
|
|
|
|
2019-09-03 01:41:11 +00:00
|
|
|
struct tray_binding *tray_bind = NULL, *tmp_tray_bind = NULL;
|
|
|
|
wl_list_for_each_safe(tray_bind, tmp_tray_bind, &config->tray_bindings,
|
|
|
|
link) {
|
|
|
|
wl_list_remove(&tray_bind->link);
|
|
|
|
free_tray_binding(tray_bind);
|
|
|
|
}
|
2018-12-09 15:10:41 +00:00
|
|
|
if ((json_object_object_get_ex(bar_config, "tray_bindings", &tray_bindings))) {
|
|
|
|
int length = json_object_array_length(tray_bindings);
|
|
|
|
for (int i = 0; i < length; ++i) {
|
|
|
|
json_object *bind = json_object_array_get_idx(tray_bindings, i);
|
2019-01-16 02:25:28 +00:00
|
|
|
struct tray_binding *binding =
|
|
|
|
calloc(1, sizeof(struct tray_binding));
|
|
|
|
binding->button = json_object_get_int(
|
|
|
|
json_object_object_get(bind, "event_code"));
|
|
|
|
binding->command = strdup(json_object_get_string(
|
|
|
|
json_object_object_get(bind, "command")));
|
|
|
|
wl_list_insert(&config->tray_bindings, &binding->link);
|
2018-12-09 15:10:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((json_object_object_get_ex(bar_config, "icon_theme", &icon_theme))) {
|
|
|
|
config->icon_theme = strdup(json_object_get_string(icon_theme));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-03-29 03:56:02 +00:00
|
|
|
json_object_put(bar_config);
|
2018-09-24 17:42:25 +00:00
|
|
|
return true;
|
2018-03-29 03:56:02 +00:00
|
|
|
}
|
|
|
|
|
2018-10-12 20:05:43 +00:00
|
|
|
bool ipc_get_workspaces(struct swaybar *bar) {
|
2018-03-29 04:21:05 +00:00
|
|
|
struct swaybar_output *output;
|
|
|
|
wl_list_for_each(output, &bar->outputs, link) {
|
|
|
|
free_workspaces(&output->workspaces);
|
2018-03-29 20:02:59 +00:00
|
|
|
output->focused = false;
|
2018-03-29 04:21:05 +00:00
|
|
|
}
|
|
|
|
uint32_t len = 0;
|
|
|
|
char *res = ipc_single_command(bar->ipc_socketfd,
|
|
|
|
IPC_GET_WORKSPACES, NULL, &len);
|
|
|
|
json_object *results = json_tokener_parse(res);
|
|
|
|
if (!results) {
|
|
|
|
free(res);
|
2018-10-12 20:05:43 +00:00
|
|
|
return false;
|
2018-03-29 04:21:05 +00:00
|
|
|
}
|
2018-10-12 20:05:43 +00:00
|
|
|
|
|
|
|
bar->visible_by_urgency = false;
|
2018-03-29 04:21:05 +00:00
|
|
|
size_t length = json_object_array_length(results);
|
|
|
|
json_object *ws_json;
|
|
|
|
json_object *num, *name, *visible, *focused, *out, *urgent;
|
|
|
|
for (size_t i = 0; i < length; ++i) {
|
|
|
|
ws_json = json_object_array_get_idx(results, i);
|
|
|
|
|
|
|
|
json_object_object_get_ex(ws_json, "num", &num);
|
|
|
|
json_object_object_get_ex(ws_json, "name", &name);
|
|
|
|
json_object_object_get_ex(ws_json, "visible", &visible);
|
|
|
|
json_object_object_get_ex(ws_json, "focused", &focused);
|
|
|
|
json_object_object_get_ex(ws_json, "output", &out);
|
|
|
|
json_object_object_get_ex(ws_json, "urgent", &urgent);
|
|
|
|
|
|
|
|
wl_list_for_each(output, &bar->outputs, link) {
|
|
|
|
const char *ws_output = json_object_get_string(out);
|
2020-05-20 20:57:56 +00:00
|
|
|
if (ws_output != NULL && strcmp(ws_output, output->name) == 0) {
|
2018-03-29 04:21:05 +00:00
|
|
|
struct swaybar_workspace *ws =
|
|
|
|
calloc(1, sizeof(struct swaybar_workspace));
|
|
|
|
ws->num = json_object_get_int(num);
|
|
|
|
ws->name = strdup(json_object_get_string(name));
|
2018-11-17 16:11:28 +00:00
|
|
|
ws->label = strdup(ws->name);
|
|
|
|
// ws->num will be -1 if workspace name doesn't begin with int.
|
|
|
|
if (ws->num != -1) {
|
2019-01-22 10:43:48 +00:00
|
|
|
size_t len_offset = snprintf(NULL, 0, "%d", ws->num);
|
2018-11-17 16:11:28 +00:00
|
|
|
if (bar->config->strip_workspace_name) {
|
|
|
|
free(ws->label);
|
2019-01-22 10:43:48 +00:00
|
|
|
ws->label = malloc(len_offset + 1);
|
|
|
|
snprintf(ws->label, len_offset + 1, "%d", ws->num);
|
2018-11-17 16:11:28 +00:00
|
|
|
} else if (bar->config->strip_workspace_numbers) {
|
|
|
|
len_offset += ws->label[len_offset] == ':';
|
2019-01-22 10:43:48 +00:00
|
|
|
if (ws->name[len_offset] != '\0') {
|
2018-11-17 16:11:28 +00:00
|
|
|
free(ws->label);
|
|
|
|
// Strip number prefix [1-?:] using len_offset.
|
|
|
|
ws->label = strdup(ws->name + len_offset);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-03-29 04:21:05 +00:00
|
|
|
ws->visible = json_object_get_boolean(visible);
|
|
|
|
ws->focused = json_object_get_boolean(focused);
|
|
|
|
if (ws->focused) {
|
|
|
|
output->focused = true;
|
|
|
|
}
|
|
|
|
ws->urgent = json_object_get_boolean(urgent);
|
2018-10-12 20:05:43 +00:00
|
|
|
if (ws->urgent) {
|
|
|
|
bar->visible_by_urgency = true;
|
|
|
|
}
|
2018-10-25 11:23:48 +00:00
|
|
|
wl_list_insert(output->workspaces.prev, &ws->link);
|
2018-03-29 04:21:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-03-29 20:02:59 +00:00
|
|
|
json_object_put(results);
|
2018-03-29 04:21:05 +00:00
|
|
|
free(res);
|
2018-10-12 20:05:43 +00:00
|
|
|
return determine_bar_visibility(bar, false);
|
2018-03-29 04:21:05 +00:00
|
|
|
}
|
|
|
|
|
2018-10-08 15:40:13 +00:00
|
|
|
void ipc_execute_binding(struct swaybar *bar, struct swaybar_binding *bind) {
|
2019-01-20 18:51:12 +00:00
|
|
|
sway_log(SWAY_DEBUG, "Executing binding for button %u (release=%d): `%s`",
|
2018-10-09 12:12:02 +00:00
|
|
|
bind->button, bind->release, bind->command);
|
2018-10-08 15:40:13 +00:00
|
|
|
uint32_t len = strlen(bind->command);
|
|
|
|
free(ipc_single_command(bar->ipc_socketfd,
|
|
|
|
IPC_COMMAND, bind->command, &len));
|
|
|
|
}
|
|
|
|
|
2018-09-30 14:09:09 +00:00
|
|
|
bool ipc_initialize(struct swaybar *bar) {
|
|
|
|
uint32_t len = strlen(bar->id);
|
2018-03-29 03:56:02 +00:00
|
|
|
char *res = ipc_single_command(bar->ipc_socketfd,
|
2018-09-30 14:09:09 +00:00
|
|
|
IPC_GET_BAR_CONFIG, bar->id, &len);
|
2018-09-24 17:42:25 +00:00
|
|
|
if (!ipc_parse_config(bar->config, res)) {
|
|
|
|
free(res);
|
|
|
|
return false;
|
|
|
|
}
|
2018-03-29 03:56:02 +00:00
|
|
|
free(res);
|
2018-03-29 14:38:17 +00:00
|
|
|
|
2023-05-04 09:27:20 +00:00
|
|
|
char *subscribe =
|
|
|
|
"[ \"barconfig_update\", \"bar_state_update\", \"mode\", \"workspace\" ]";
|
|
|
|
len = strlen(subscribe);
|
2018-03-29 14:38:17 +00:00
|
|
|
free(ipc_single_command(bar->ipc_event_socketfd,
|
|
|
|
IPC_SUBSCRIBE, subscribe, &len));
|
2018-09-24 17:42:25 +00:00
|
|
|
return true;
|
2018-03-29 03:56:02 +00:00
|
|
|
}
|
|
|
|
|
2018-10-12 20:14:52 +00:00
|
|
|
static bool handle_bar_state_update(struct swaybar *bar, json_object *event) {
|
|
|
|
json_object *json_id;
|
|
|
|
json_object_object_get_ex(event, "id", &json_id);
|
|
|
|
const char *id = json_object_get_string(json_id);
|
|
|
|
if (strcmp(id, bar->id) != 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
json_object *visible_by_modifier;
|
|
|
|
json_object_object_get_ex(event, "visible_by_modifier", &visible_by_modifier);
|
|
|
|
bar->visible_by_modifier = json_object_get_boolean(visible_by_modifier);
|
2019-04-24 04:25:49 +00:00
|
|
|
if (bar->visible_by_modifier) {
|
|
|
|
// If the bar is visible by modifier, clear both visible by mode and
|
|
|
|
// urgency as modifier has precedence and the bar should be hidden
|
|
|
|
// again when it is no longer visible by modifier.
|
|
|
|
bar->visible_by_mode = false;
|
|
|
|
bar->visible_by_urgency = false;
|
|
|
|
}
|
2018-10-12 20:14:52 +00:00
|
|
|
return determine_bar_visibility(bar, false);
|
|
|
|
}
|
|
|
|
|
2019-09-03 01:41:11 +00:00
|
|
|
static bool handle_barconfig_update(struct swaybar *bar, const char *payload,
|
2018-10-12 19:32:48 +00:00
|
|
|
json_object *json_config) {
|
2019-09-03 01:41:11 +00:00
|
|
|
json_object *json_id = json_object_object_get(json_config, "id");
|
2018-10-12 19:32:48 +00:00
|
|
|
const char *id = json_object_get_string(json_id);
|
|
|
|
if (strcmp(id, bar->id) != 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-09-03 01:41:11 +00:00
|
|
|
struct swaybar_config *newcfg = init_config();
|
|
|
|
ipc_parse_config(newcfg, payload);
|
2018-10-12 19:32:48 +00:00
|
|
|
|
2019-09-03 01:41:11 +00:00
|
|
|
struct swaybar_config *oldcfg = bar->config;
|
|
|
|
bar->config = newcfg;
|
|
|
|
|
|
|
|
struct swaybar_output *output, *tmp_output;
|
|
|
|
wl_list_for_each_safe(output, tmp_output, &bar->outputs, link) {
|
|
|
|
bool found = wl_list_empty(&newcfg->outputs);
|
|
|
|
struct config_output *coutput;
|
|
|
|
wl_list_for_each(coutput, &newcfg->outputs, link) {
|
|
|
|
if (strcmp(coutput->name, output->name) == 0 ||
|
|
|
|
strcmp(coutput->name, output->identifier) == 0) {
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
2018-11-28 16:23:48 +00:00
|
|
|
}
|
2019-09-03 01:41:11 +00:00
|
|
|
if (!found) {
|
|
|
|
destroy_layer_surface(output);
|
|
|
|
wl_list_remove(&output->link);
|
|
|
|
wl_list_insert(&bar->unused_outputs, &output->link);
|
2022-07-01 10:23:04 +00:00
|
|
|
} else if (!pango_font_description_equal(oldcfg->font_description, newcfg->font_description)) {
|
2019-09-03 01:41:11 +00:00
|
|
|
output->height = 0; // force update height
|
2018-11-28 16:23:48 +00:00
|
|
|
}
|
2019-09-03 01:41:11 +00:00
|
|
|
}
|
|
|
|
wl_list_for_each_safe(output, tmp_output, &bar->unused_outputs, link) {
|
|
|
|
bool found = wl_list_empty(&newcfg->outputs);
|
|
|
|
struct config_output *coutput;
|
|
|
|
wl_list_for_each(coutput, &newcfg->outputs, link) {
|
|
|
|
if (strcmp(coutput->name, output->name) == 0 ||
|
|
|
|
strcmp(coutput->name, output->identifier) == 0) {
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
2018-11-28 16:23:48 +00:00
|
|
|
}
|
2019-09-03 01:41:11 +00:00
|
|
|
if (found) {
|
|
|
|
wl_list_remove(&output->link);
|
|
|
|
wl_list_insert(&bar->outputs, &output->link);
|
2018-11-28 16:23:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-03 01:41:11 +00:00
|
|
|
if (bar->status && (!newcfg->status_command ||
|
|
|
|
strcmp(newcfg->status_command, oldcfg->status_command) != 0)) {
|
|
|
|
status_line_free(bar->status);
|
|
|
|
bar->status = NULL;
|
|
|
|
}
|
|
|
|
if (!bar->status && newcfg->status_command) {
|
|
|
|
bar->status = status_line_init(newcfg->status_command);
|
|
|
|
bar->status->bar = bar;
|
|
|
|
loop_add_fd(bar->eventloop, bar->status->read_fd, POLLIN,
|
|
|
|
status_in, bar);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if HAVE_TRAY
|
|
|
|
if (oldcfg->tray_hidden && !newcfg->tray_hidden) {
|
|
|
|
bar->tray = create_tray(bar);
|
|
|
|
loop_add_fd(bar->eventloop, bar->tray->fd, POLLIN, tray_in,
|
|
|
|
bar->tray->bus);
|
|
|
|
} else if (bar->tray && newcfg->tray_hidden) {
|
|
|
|
loop_remove_fd(bar->eventloop, bar->tray->fd);
|
|
|
|
destroy_tray(bar->tray);
|
|
|
|
bar->tray = NULL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (newcfg->workspace_buttons) {
|
|
|
|
ipc_get_workspaces(bar);
|
|
|
|
}
|
|
|
|
|
2020-02-27 04:36:14 +00:00
|
|
|
bool moving_layer = strcmp(oldcfg->mode, newcfg->mode) != 0;
|
|
|
|
|
2019-09-03 01:41:11 +00:00
|
|
|
free_config(oldcfg);
|
2020-02-27 04:36:14 +00:00
|
|
|
determine_bar_visibility(bar, moving_layer);
|
2019-09-03 01:41:11 +00:00
|
|
|
return true;
|
2018-10-12 19:32:48 +00:00
|
|
|
}
|
|
|
|
|
2018-03-31 18:39:18 +00:00
|
|
|
bool handle_ipc_readable(struct swaybar *bar) {
|
2018-03-29 03:56:02 +00:00
|
|
|
struct ipc_response *resp = ipc_recv_response(bar->ipc_event_socketfd);
|
2018-03-29 14:38:17 +00:00
|
|
|
if (!resp) {
|
|
|
|
return false;
|
|
|
|
}
|
2018-10-12 19:28:04 +00:00
|
|
|
|
2021-03-22 13:01:00 +00:00
|
|
|
// The default depth of 32 is too small to represent some nested layouts, but
|
|
|
|
// we can't pass INT_MAX here because json-c (as of this writing) prefaults
|
|
|
|
// all the memory for its stack.
|
2021-10-25 04:28:32 +00:00
|
|
|
json_tokener *tok = json_tokener_new_ex(JSON_MAX_DEPTH);
|
2021-03-22 13:01:00 +00:00
|
|
|
if (!tok) {
|
|
|
|
sway_log_errno(SWAY_ERROR, "failed to create tokener");
|
|
|
|
free_ipc_response(resp);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-03-21 21:14:16 +00:00
|
|
|
json_object *result = json_tokener_parse_ex(tok, resp->payload, -1);
|
|
|
|
enum json_tokener_error err = json_tokener_get_error(tok);
|
|
|
|
json_tokener_free(tok);
|
|
|
|
|
|
|
|
if (err != json_tokener_success) {
|
|
|
|
sway_log(SWAY_ERROR, "failed to parse payload as json: %s",
|
|
|
|
json_tokener_error_desc(err));
|
2018-10-12 19:28:04 +00:00
|
|
|
free_ipc_response(resp);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool bar_is_dirty = true;
|
2018-03-29 14:38:17 +00:00
|
|
|
switch (resp->type) {
|
|
|
|
case IPC_EVENT_WORKSPACE:
|
2018-10-12 20:05:43 +00:00
|
|
|
bar_is_dirty = ipc_get_workspaces(bar);
|
2018-04-10 20:01:22 +00:00
|
|
|
break;
|
2018-03-29 14:38:17 +00:00
|
|
|
case IPC_EVENT_MODE: {
|
2018-03-29 15:58:54 +00:00
|
|
|
json_object *json_change, *json_pango_markup;
|
2018-03-29 14:38:17 +00:00
|
|
|
if (json_object_object_get_ex(result, "change", &json_change)) {
|
|
|
|
const char *change = json_object_get_string(json_change);
|
2018-10-12 19:23:01 +00:00
|
|
|
free(bar->mode);
|
|
|
|
bar->mode = strcmp(change, "default") != 0 ? strdup(change) : NULL;
|
2019-04-24 04:25:49 +00:00
|
|
|
bar->visible_by_mode = bar->mode != NULL;
|
|
|
|
determine_bar_visibility(bar, false);
|
2018-03-29 14:38:17 +00:00
|
|
|
} else {
|
2019-01-20 18:51:12 +00:00
|
|
|
sway_log(SWAY_ERROR, "failed to parse response");
|
2018-10-12 19:28:04 +00:00
|
|
|
bar_is_dirty = false;
|
|
|
|
break;
|
2018-03-29 14:38:17 +00:00
|
|
|
}
|
2018-03-29 15:58:54 +00:00
|
|
|
if (json_object_object_get_ex(result,
|
|
|
|
"pango_markup", &json_pango_markup)) {
|
2018-10-12 19:23:01 +00:00
|
|
|
bar->mode_pango_markup = json_object_get_boolean(json_pango_markup);
|
2018-03-29 15:58:54 +00:00
|
|
|
}
|
2018-03-29 14:38:17 +00:00
|
|
|
break;
|
|
|
|
}
|
2018-10-12 19:32:48 +00:00
|
|
|
case IPC_EVENT_BARCONFIG_UPDATE:
|
2019-09-03 01:41:11 +00:00
|
|
|
bar_is_dirty = handle_barconfig_update(bar, resp->payload, result);
|
2018-10-12 19:32:48 +00:00
|
|
|
break;
|
2018-10-12 20:14:52 +00:00
|
|
|
case IPC_EVENT_BAR_STATE_UPDATE:
|
|
|
|
bar_is_dirty = handle_bar_state_update(bar, result);
|
|
|
|
break;
|
2018-03-29 14:38:17 +00:00
|
|
|
default:
|
2018-10-12 19:28:04 +00:00
|
|
|
bar_is_dirty = false;
|
|
|
|
break;
|
2018-03-29 14:38:17 +00:00
|
|
|
}
|
2018-10-12 19:28:04 +00:00
|
|
|
json_object_put(result);
|
2018-03-29 03:56:02 +00:00
|
|
|
free_ipc_response(resp);
|
2018-10-12 19:28:04 +00:00
|
|
|
return bar_is_dirty;
|
2018-03-29 03:56:02 +00:00
|
|
|
}
|