You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
272 lines
7.1 KiB
272 lines
7.1 KiB
#define _POSIX_C_SOURCE 200809L
|
|
#include <signal.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <strings.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#include <unistd.h>
|
|
#include <wordexp.h>
|
|
#include "sway/config.h"
|
|
#include "sway/input/keyboard.h"
|
|
#include "sway/output.h"
|
|
#include "config.h"
|
|
#include "list.h"
|
|
#include "log.h"
|
|
#include "stringop.h"
|
|
#include "util.h"
|
|
|
|
void free_bar_binding(struct bar_binding *binding) {
|
|
if (!binding) {
|
|
return;
|
|
}
|
|
free(binding->command);
|
|
free(binding);
|
|
}
|
|
|
|
void free_bar_config(struct bar_config *bar) {
|
|
if (!bar) {
|
|
return;
|
|
}
|
|
free(bar->id);
|
|
free(bar->mode);
|
|
free(bar->position);
|
|
free(bar->hidden_state);
|
|
free(bar->status_command);
|
|
free(bar->swaybar_command);
|
|
free(bar->font);
|
|
free(bar->separator_symbol);
|
|
if (bar->bindings) {
|
|
for (int i = 0; i < bar->bindings->length; i++) {
|
|
free_bar_binding(bar->bindings->items[i]);
|
|
}
|
|
}
|
|
list_free(bar->bindings);
|
|
list_free_items_and_destroy(bar->outputs);
|
|
if (bar->client != NULL) {
|
|
wl_client_destroy(bar->client);
|
|
}
|
|
free(bar->colors.background);
|
|
free(bar->colors.statusline);
|
|
free(bar->colors.separator);
|
|
free(bar->colors.focused_background);
|
|
free(bar->colors.focused_statusline);
|
|
free(bar->colors.focused_separator);
|
|
free(bar->colors.focused_workspace_border);
|
|
free(bar->colors.focused_workspace_bg);
|
|
free(bar->colors.focused_workspace_text);
|
|
free(bar->colors.active_workspace_border);
|
|
free(bar->colors.active_workspace_bg);
|
|
free(bar->colors.active_workspace_text);
|
|
free(bar->colors.inactive_workspace_border);
|
|
free(bar->colors.inactive_workspace_bg);
|
|
free(bar->colors.inactive_workspace_text);
|
|
free(bar->colors.urgent_workspace_border);
|
|
free(bar->colors.urgent_workspace_bg);
|
|
free(bar->colors.urgent_workspace_text);
|
|
free(bar->colors.binding_mode_border);
|
|
free(bar->colors.binding_mode_bg);
|
|
free(bar->colors.binding_mode_text);
|
|
#if HAVE_TRAY
|
|
list_free_items_and_destroy(bar->tray_outputs);
|
|
free(bar->icon_theme);
|
|
|
|
struct tray_binding *tray_bind = NULL, *tmp_tray_bind = NULL;
|
|
wl_list_for_each_safe(tray_bind, tmp_tray_bind, &bar->tray_bindings, link) {
|
|
wl_list_remove(&tray_bind->link);
|
|
free(tray_bind);
|
|
}
|
|
#endif
|
|
free(bar);
|
|
}
|
|
|
|
struct bar_config *default_bar_config(void) {
|
|
struct bar_config *bar = NULL;
|
|
bar = calloc(1, sizeof(struct bar_config));
|
|
if (!bar) {
|
|
return NULL;
|
|
}
|
|
bar->outputs = NULL;
|
|
bar->position = strdup("bottom");
|
|
bar->pango_markup = false;
|
|
bar->swaybar_command = NULL;
|
|
bar->font = NULL;
|
|
bar->height = 0;
|
|
bar->workspace_buttons = true;
|
|
bar->wrap_scroll = false;
|
|
bar->separator_symbol = NULL;
|
|
bar->strip_workspace_numbers = false;
|
|
bar->strip_workspace_name = false;
|
|
bar->binding_mode_indicator = true;
|
|
bar->verbose = false;
|
|
bar->modifier = get_modifier_mask_by_name("Mod4");
|
|
bar->status_padding = 1;
|
|
bar->status_edge_padding = 3;
|
|
if (!(bar->mode = strdup("dock"))) {
|
|
goto cleanup;
|
|
}
|
|
if (!(bar->hidden_state = strdup("hide"))) {
|
|
goto cleanup;
|
|
}
|
|
if (!(bar->bindings = create_list())) {
|
|
goto cleanup;
|
|
}
|
|
// set default colors
|
|
if (!(bar->colors.background = strndup("#000000ff", 9))) {
|
|
goto cleanup;
|
|
}
|
|
if (!(bar->colors.statusline = strndup("#ffffffff", 9))) {
|
|
goto cleanup;
|
|
}
|
|
if (!(bar->colors.separator = strndup("#666666ff", 9))) {
|
|
goto cleanup;
|
|
}
|
|
if (!(bar->colors.focused_workspace_border = strndup("#4c7899ff", 9))) {
|
|
goto cleanup;
|
|
}
|
|
if (!(bar->colors.focused_workspace_bg = strndup("#285577ff", 9))) {
|
|
goto cleanup;
|
|
}
|
|
if (!(bar->colors.focused_workspace_text = strndup("#ffffffff", 9))) {
|
|
goto cleanup;
|
|
}
|
|
if (!(bar->colors.active_workspace_border = strndup("#333333ff", 9))) {
|
|
goto cleanup;
|
|
}
|
|
if (!(bar->colors.active_workspace_bg = strndup("#5f676aff", 9))) {
|
|
goto cleanup;
|
|
}
|
|
if (!(bar->colors.active_workspace_text = strndup("#ffffffff", 9))) {
|
|
goto cleanup;
|
|
}
|
|
if (!(bar->colors.inactive_workspace_border = strndup("#333333ff", 9))) {
|
|
goto cleanup;
|
|
}
|
|
if (!(bar->colors.inactive_workspace_bg = strndup("#222222ff", 9))) {
|
|
goto cleanup;
|
|
}
|
|
if (!(bar->colors.inactive_workspace_text = strndup("#888888ff", 9))) {
|
|
goto cleanup;
|
|
}
|
|
if (!(bar->colors.urgent_workspace_border = strndup("#2f343aff", 9))) {
|
|
goto cleanup;
|
|
}
|
|
if (!(bar->colors.urgent_workspace_bg = strndup("#900000ff", 9))) {
|
|
goto cleanup;
|
|
}
|
|
if (!(bar->colors.urgent_workspace_text = strndup("#ffffffff", 9))) {
|
|
goto cleanup;
|
|
}
|
|
// if the following colors stay undefined, they fall back to background,
|
|
// statusline, separator and urgent_workspace_*.
|
|
bar->colors.focused_background = NULL;
|
|
bar->colors.focused_statusline = NULL;
|
|
bar->colors.focused_separator = NULL;
|
|
bar->colors.binding_mode_border = NULL;
|
|
bar->colors.binding_mode_bg = NULL;
|
|
bar->colors.binding_mode_text = NULL;
|
|
|
|
#if HAVE_TRAY
|
|
bar->tray_padding = 2;
|
|
wl_list_init(&bar->tray_bindings);
|
|
#endif
|
|
|
|
return bar;
|
|
cleanup:
|
|
free_bar_config(bar);
|
|
return NULL;
|
|
}
|
|
|
|
static void handle_swaybar_client_destroy(struct wl_listener *listener,
|
|
void *data) {
|
|
struct bar_config *bar = wl_container_of(listener, bar, client_destroy);
|
|
wl_list_remove(&bar->client_destroy.link);
|
|
wl_list_init(&bar->client_destroy.link);
|
|
bar->client = NULL;
|
|
}
|
|
|
|
static void invoke_swaybar(struct bar_config *bar) {
|
|
int sockets[2];
|
|
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) != 0) {
|
|
sway_log_errno(SWAY_ERROR, "socketpair failed");
|
|
return;
|
|
}
|
|
if (!set_cloexec(sockets[0], true) || !set_cloexec(sockets[1], true)) {
|
|
return;
|
|
}
|
|
|
|
bar->client = wl_client_create(server.wl_display, sockets[0]);
|
|
if (bar->client == NULL) {
|
|
sway_log_errno(SWAY_ERROR, "wl_client_create failed");
|
|
return;
|
|
}
|
|
|
|
bar->client_destroy.notify = handle_swaybar_client_destroy;
|
|
wl_client_add_destroy_listener(bar->client, &bar->client_destroy);
|
|
|
|
pid_t pid = fork();
|
|
if (pid < 0) {
|
|
sway_log(SWAY_ERROR, "Failed to create fork for swaybar");
|
|
return;
|
|
} else if (pid == 0) {
|
|
// Remove the SIGUSR1 handler that wlroots adds for xwayland
|
|
sigset_t set;
|
|
sigemptyset(&set);
|
|
sigprocmask(SIG_SETMASK, &set, NULL);
|
|
|
|
pid = fork();
|
|
if (pid < 0) {
|
|
sway_log_errno(SWAY_ERROR, "fork failed");
|
|
_exit(EXIT_FAILURE);
|
|
} else if (pid == 0) {
|
|
if (!set_cloexec(sockets[1], false)) {
|
|
_exit(EXIT_FAILURE);
|
|
}
|
|
|
|
char wayland_socket_str[16];
|
|
snprintf(wayland_socket_str, sizeof(wayland_socket_str),
|
|
"%d", sockets[1]);
|
|
setenv("WAYLAND_SOCKET", wayland_socket_str, true);
|
|
|
|
// run custom swaybar
|
|
char *const cmd[] = {
|
|
bar->swaybar_command ? bar->swaybar_command : "swaybar",
|
|
"-b", bar->id, NULL};
|
|
execvp(cmd[0], cmd);
|
|
_exit(EXIT_FAILURE);
|
|
}
|
|
_exit(EXIT_SUCCESS);
|
|
}
|
|
|
|
if (close(sockets[1]) != 0) {
|
|
sway_log_errno(SWAY_ERROR, "close failed");
|
|
return;
|
|
}
|
|
|
|
if (waitpid(pid, NULL, 0) < 0) {
|
|
sway_log_errno(SWAY_ERROR, "waitpid failed");
|
|
return;
|
|
}
|
|
|
|
sway_log(SWAY_DEBUG, "Spawned swaybar %s", bar->id);
|
|
return;
|
|
}
|
|
|
|
void load_swaybar(struct bar_config *bar) {
|
|
if (bar->client != NULL) {
|
|
wl_client_destroy(bar->client);
|
|
}
|
|
sway_log(SWAY_DEBUG, "Invoking swaybar for bar id '%s'", bar->id);
|
|
invoke_swaybar(bar);
|
|
}
|
|
|
|
void load_swaybars(void) {
|
|
for (int i = 0; i < config->bars->length; ++i) {
|
|
struct bar_config *bar = config->bars->items[i];
|
|
load_swaybar(bar);
|
|
}
|
|
}
|