Merge pull request #2751 from ianyfan/swaybar

Bar mode/hidden_state events
This commit is contained in:
Drew DeVault 2018-10-14 15:13:50 +02:00 committed by GitHub
commit 4a05fbf8ab
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 372 additions and 144 deletions

View file

@ -30,6 +30,9 @@ enum ipc_command_type {
IPC_EVENT_BINDING = ((1<<31) | 5), IPC_EVENT_BINDING = ((1<<31) | 5),
IPC_EVENT_SHUTDOWN = ((1<<31) | 6), IPC_EVENT_SHUTDOWN = ((1<<31) | 6),
IPC_EVENT_TICK = ((1<<31) | 7), IPC_EVENT_TICK = ((1<<31) | 7),
// sway-specific event types
IPC_EVENT_BAR_STATE_UPDATE = ((1<<31) | 20),
}; };
#endif #endif

View file

@ -191,6 +191,7 @@ struct bar_config {
* In "show" mode, it will always be shown on top of the active workspace. * In "show" mode, it will always be shown on top of the active workspace.
*/ */
char *hidden_state; char *hidden_state;
bool visible_by_modifier; // only relevant in "hide" mode
/** /**
* Id name used to identify the bar through IPC. * Id name used to identify the bar through IPC.
* *

View file

@ -15,6 +15,7 @@ void ipc_event_workspace(struct sway_workspace *old,
struct sway_workspace *new, const char *change); struct sway_workspace *new, const char *change);
void ipc_event_window(struct sway_container *window, const char *change); void ipc_event_window(struct sway_container *window, const char *change);
void ipc_event_barconfig_update(struct bar_config *bar); void ipc_event_barconfig_update(struct bar_config *bar);
void ipc_event_bar_state_update(struct bar_config *bar);
void ipc_event_mode(const char *mode, bool pango); void ipc_event_mode(const char *mode, bool pango);
void ipc_event_shutdown(const char *reason); void ipc_event_shutdown(const char *reason);
void ipc_event_binding(struct sway_binding *binding); void ipc_event_binding(struct sway_binding *binding);

View file

@ -37,7 +37,7 @@ enum hotspot_event_handling {
}; };
struct swaybar_hotspot { struct swaybar_hotspot {
struct wl_list link; struct wl_list link; // swaybar_output::hotspots
int x, y, width, height; int x, y, width, height;
enum hotspot_event_handling (*callback)(struct swaybar_output *output, enum hotspot_event_handling (*callback)(struct swaybar_output *output,
int x, int y, enum x11_button button, void *data); int x, int y, enum x11_button button, void *data);
@ -46,6 +46,15 @@ struct swaybar_hotspot {
}; };
struct swaybar { struct swaybar {
char *id;
char *mode;
bool mode_pango_markup;
// only relevant when bar is in "hide" mode
bool visible_by_modifier;
bool visible_by_urgency;
bool visible;
struct wl_display *display; struct wl_display *display;
struct wl_compositor *compositor; struct wl_compositor *compositor;
struct zwlr_layer_shell_v1 *layer_shell; struct zwlr_layer_shell_v1 *layer_shell;
@ -60,11 +69,11 @@ struct swaybar {
int ipc_event_socketfd; int ipc_event_socketfd;
int ipc_socketfd; int ipc_socketfd;
struct wl_list outputs; struct wl_list outputs; // swaybar_output::link
}; };
struct swaybar_output { struct swaybar_output {
struct wl_list link; struct wl_list link; // swaybar::outputs
struct swaybar *bar; struct swaybar *bar;
struct wl_output *output; struct wl_output *output;
struct zxdg_output_v1 *xdg_output; struct zxdg_output_v1 *xdg_output;
@ -72,8 +81,8 @@ struct swaybar_output {
struct zwlr_layer_surface_v1 *layer_surface; struct zwlr_layer_surface_v1 *layer_surface;
uint32_t wl_name; uint32_t wl_name;
struct wl_list workspaces; struct wl_list workspaces; // swaybar_workspace::link
struct wl_list hotspots; struct wl_list hotspots; // swaybar_hotspot::link
char *name; char *name;
bool focused; bool focused;
@ -88,7 +97,7 @@ struct swaybar_output {
}; };
struct swaybar_workspace { struct swaybar_workspace {
struct wl_list link; struct wl_list link; // swaybar_output::workspaces
int num; int num;
char *name; char *name;
bool focused; bool focused;
@ -96,10 +105,24 @@ struct swaybar_workspace {
bool urgent; bool urgent;
}; };
bool bar_setup(struct swaybar *bar, const char *socket_path, const char *bar_id); bool bar_setup(struct swaybar *bar, const char *socket_path);
void bar_run(struct swaybar *bar); void bar_run(struct swaybar *bar);
void bar_teardown(struct swaybar *bar); void bar_teardown(struct swaybar *bar);
/*
* Determines whether the bar should be visible and changes it to be so.
* If the current visibility of the bar is the different to what it should be,
* then it adds or destroys the layer surface as required,
* as well as sending the cont or stop signal to the status command.
* If the current visibility of the bar is already what it should be,
* then this function is a no-op, unless moving_layer is true, which occurs
* when the bar changes from "hide" to "dock" mode or vice versa, and the bar
* needs to be destroyed and re-added in order to change its layer.
*
* Returns true if the bar is now visible, otherwise false.
*/
bool determine_bar_visibility(struct swaybar *bar, bool moving_layer);
void free_hotspots(struct wl_list *list);
void free_workspaces(struct wl_list *list); void free_workspaces(struct wl_list *list);
#endif #endif

View file

@ -13,7 +13,7 @@ struct box_colors {
}; };
struct config_output { struct config_output {
struct wl_list link; struct wl_list link; // swaybar_config::outputs
char *name; char *name;
size_t index; size_t index;
}; };
@ -31,7 +31,8 @@ struct swaybar_config {
char *font; char *font;
char *sep_symbol; char *sep_symbol;
char *mode; char *mode;
bool mode_pango_markup; char *hidden_state;
char *modifier;
bool strip_workspace_numbers; bool strip_workspace_numbers;
bool binding_mode_indicator; bool binding_mode_indicator;
bool wrap_scroll; bool wrap_scroll;

View file

@ -5,7 +5,7 @@
#include "status_line.h" #include "status_line.h"
struct i3bar_block { struct i3bar_block {
struct wl_list link; struct wl_list link; // status_link::blocks
int ref_count; int ref_count;
char *full_text, *short_text, *align; char *full_text, *short_text, *align;
bool urgent; bool urgent;

View file

@ -3,9 +3,9 @@
#include <stdbool.h> #include <stdbool.h>
#include "swaybar/bar.h" #include "swaybar/bar.h"
bool ipc_initialize(struct swaybar *bar, const char *bar_id); bool ipc_initialize(struct swaybar *bar);
bool handle_ipc_readable(struct swaybar *bar); bool handle_ipc_readable(struct swaybar *bar);
void ipc_get_workspaces(struct swaybar *bar); bool ipc_get_workspaces(struct swaybar *bar);
void ipc_send_workspace_command(struct swaybar *bar, const char *ws); void ipc_send_workspace_command(struct swaybar *bar, const char *ws);
void ipc_execute_binding(struct swaybar *bar, struct swaybar_binding *bind); void ipc_execute_binding(struct swaybar *bar, struct swaybar_binding *bind);

View file

@ -22,6 +22,9 @@ struct status_line {
const char *text; const char *text;
struct wl_list blocks; // i3bar_block::link struct wl_list blocks; // i3bar_block::link
int stop_signal;
int cont_signal;
bool click_events; bool click_events;
bool clicked; bool clicked;
char *buffer; char *buffer;

View file

@ -32,7 +32,7 @@ static struct cmd_results *bar_set_hidden_state(struct bar_config *bar,
} }
// free old mode // free old mode
free(old_state); free(old_state);
return cmd_results_new(CMD_SUCCESS, NULL, NULL); return NULL;
} }
struct cmd_results *bar_cmd_hidden_state(int argc, char **argv) { struct cmd_results *bar_cmd_hidden_state(int argc, char **argv) {
@ -50,24 +50,20 @@ struct cmd_results *bar_cmd_hidden_state(int argc, char **argv) {
const char *state = argv[0]; const char *state = argv[0];
if (config->reading) { if (config->reading) {
return bar_set_hidden_state(config->current_bar, state); error = bar_set_hidden_state(config->current_bar, state);
} } else {
const char *id = argc == 2 ? argv[1] : NULL;
const char *id = NULL; for (int i = 0; i < config->bars->length; ++i) {
if (argc == 2) { struct bar_config *bar = config->bars->items[i];
id = argv[1]; if (id) {
} if (strcmp(id, bar->id) == 0) {
struct bar_config *bar; error = bar_set_hidden_state(bar, state);
for (int i = 0; i < config->bars->length; ++i) { break;
bar = config->bars->items[i]; }
if (id && strcmp(id, bar->id) == 0) { } else if ((error = bar_set_hidden_state(bar, state))) {
return bar_set_hidden_state(bar, state); break;
} }
error = bar_set_hidden_state(bar, state);
if (error) {
return error;
} }
} }
return cmd_results_new(CMD_SUCCESS, NULL, NULL); return error ? error : cmd_results_new(CMD_SUCCESS, NULL, NULL);
} }

View file

@ -33,7 +33,7 @@ static struct cmd_results *bar_set_mode(struct bar_config *bar, const char *mode
// free old mode // free old mode
free(old_mode); free(old_mode);
return cmd_results_new(CMD_SUCCESS, NULL, NULL); return NULL;
} }
struct cmd_results *bar_cmd_mode(int argc, char **argv) { struct cmd_results *bar_cmd_mode(int argc, char **argv) {
@ -51,24 +51,20 @@ struct cmd_results *bar_cmd_mode(int argc, char **argv) {
const char *mode = argv[0]; const char *mode = argv[0];
if (config->reading) { if (config->reading) {
return bar_set_mode(config->current_bar, mode); error = bar_set_mode(config->current_bar, mode);
} } else {
const char *id = argc == 2 ? argv[1] : NULL;
const char *id = NULL; for (int i = 0; i < config->bars->length; ++i) {
if (argc == 2) { struct bar_config *bar = config->bars->items[i];
id = argv[1]; if (id) {
} if (strcmp(id, bar->id) == 0) {
error = bar_set_mode(bar, mode);
struct bar_config *bar; break;
for (int i = 0; i < config->bars->length; ++i) { }
bar = config->bars->items[i]; } else if ((error = bar_set_mode(bar, mode))) {
if (id && strcmp(id, bar->id) == 0) { break;
return bar_set_mode(bar, mode); }
}
error = bar_set_mode(bar, mode);
if (error) {
return error;
} }
} }
return cmd_results_new(CMD_SUCCESS, NULL, NULL); return error ? error : cmd_results_new(CMD_SUCCESS, NULL, NULL);
} }

View file

@ -16,6 +16,7 @@
#include "stringop.h" #include "stringop.h"
#include "list.h" #include "list.h"
#include "log.h" #include "log.h"
#include "util.h"
static void terminate_swaybar(pid_t pid) { static void terminate_swaybar(pid_t pid) {
wlr_log(WLR_DEBUG, "Terminating swaybar %d", pid); wlr_log(WLR_DEBUG, "Terminating swaybar %d", pid);
@ -101,6 +102,7 @@ struct bar_config *default_bar_config(void) {
bar->binding_mode_indicator = true; bar->binding_mode_indicator = true;
bar->verbose = false; bar->verbose = false;
bar->pid = 0; bar->pid = 0;
bar->modifier = get_modifier_mask_by_name("Mod4");
if (!(bar->mode = strdup("dock"))) { if (!(bar->mode = strdup("dock"))) {
goto cleanup; goto cleanup;
} }

View file

@ -9,6 +9,7 @@
#include "sway/input/input-manager.h" #include "sway/input/input-manager.h"
#include "sway/input/keyboard.h" #include "sway/input/keyboard.h"
#include "sway/input/seat.h" #include "sway/input/seat.h"
#include "sway/ipc-server.h"
#include "log.h" #include "log.h"
/** /**
@ -66,10 +67,10 @@ static void update_shortcut_state(struct sway_shortcut_state *state,
bool last_key_was_a_modifier = raw_modifiers != state->last_raw_modifiers; bool last_key_was_a_modifier = raw_modifiers != state->last_raw_modifiers;
state->last_raw_modifiers = raw_modifiers; state->last_raw_modifiers = raw_modifiers;
if (last_key_was_a_modifier && state->last_keycode) { if (last_key_was_a_modifier && state->last_keycode) {
// Last pressed key before this one was a modifier // Last pressed key before this one was a modifier
state_erase_key(state, state->last_keycode); state_erase_key(state, state->last_keycode);
} }
if (event->state == WLR_KEY_PRESSED) { if (event->state == WLR_KEY_PRESSED) {
// Add current key to set; there may be duplicates // Add current key to set; there may be duplicates
@ -235,7 +236,6 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) {
code_modifiers); code_modifiers);
} }
bool handled = false; bool handled = false;
// Identify active release binding // Identify active release binding
@ -337,6 +337,19 @@ static int handle_keyboard_repeat(void *data) {
return 0; return 0;
} }
static void determine_bar_visibility(uint32_t modifiers) {
for (int i = 0; i < config->bars->length; ++i) {
struct bar_config *bar = config->bars->items[i];
if (strcmp(bar->mode, bar->hidden_state) == 0) { // both are "hide"
bool should_be_visible = (~modifiers & bar->modifier) == 0;
if (bar->visible_by_modifier != should_be_visible) {
bar->visible_by_modifier = should_be_visible;
ipc_event_bar_state_update(bar);
}
}
}
}
static void handle_keyboard_modifiers(struct wl_listener *listener, static void handle_keyboard_modifiers(struct wl_listener *listener,
void *data) { void *data) {
struct sway_keyboard *keyboard = struct sway_keyboard *keyboard =
@ -346,6 +359,9 @@ static void handle_keyboard_modifiers(struct wl_listener *listener,
keyboard->seat_device->input_device->wlr_device; keyboard->seat_device->input_device->wlr_device;
wlr_seat_set_keyboard(wlr_seat, wlr_device); wlr_seat_set_keyboard(wlr_seat, wlr_device);
wlr_seat_keyboard_notify_modifiers(wlr_seat, &wlr_device->keyboard->modifiers); wlr_seat_keyboard_notify_modifiers(wlr_seat, &wlr_device->keyboard->modifiers);
uint32_t modifiers = wlr_keyboard_get_modifiers(wlr_device->keyboard);
determine_bar_visibility(modifiers);
} }
struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat, struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat,
@ -464,7 +480,7 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) {
keyboard->keyboard_key.notify = handle_keyboard_key; keyboard->keyboard_key.notify = handle_keyboard_key;
wl_list_remove(&keyboard->keyboard_modifiers.link); wl_list_remove(&keyboard->keyboard_modifiers.link);
wl_signal_add( &wlr_device->keyboard->events.modifiers, wl_signal_add(&wlr_device->keyboard->events.modifiers,
&keyboard->keyboard_modifiers); &keyboard->keyboard_modifiers);
keyboard->keyboard_modifiers.notify = handle_keyboard_modifiers; keyboard->keyboard_modifiers.notify = handle_keyboard_modifiers;
} }

View file

@ -349,6 +349,22 @@ void ipc_event_barconfig_update(struct bar_config *bar) {
json_object_put(json); json_object_put(json);
} }
void ipc_event_bar_state_update(struct bar_config *bar) {
if (!ipc_has_event_listeners(IPC_EVENT_BAR_STATE_UPDATE)) {
return;
}
wlr_log(WLR_DEBUG, "Sending bar_state_update event");
json_object *json = json_object_new_object();
json_object_object_add(json, "id", json_object_new_string(bar->id));
json_object_object_add(json, "visible_by_modifier",
json_object_new_boolean(bar->visible_by_modifier));
const char *json_string = json_object_to_json_string(json);
ipc_send_event(json_string, IPC_EVENT_BAR_STATE_UPDATE);
json_object_put(json);
}
void ipc_event_mode(const char *mode, bool pango) { void ipc_event_mode(const char *mode, bool pango) {
if (!ipc_has_event_listeners(IPC_EVENT_MODE)) { if (!ipc_has_event_listeners(IPC_EVENT_MODE)) {
return; return;
@ -651,6 +667,8 @@ void ipc_client_handle_command(struct ipc_client *client) {
client->subscribed_events |= event_mask(IPC_EVENT_WORKSPACE); client->subscribed_events |= event_mask(IPC_EVENT_WORKSPACE);
} else if (strcmp(event_type, "barconfig_update") == 0) { } else if (strcmp(event_type, "barconfig_update") == 0) {
client->subscribed_events |= event_mask(IPC_EVENT_BARCONFIG_UPDATE); client->subscribed_events |= event_mask(IPC_EVENT_BARCONFIG_UPDATE);
} else if (strcmp(event_type, "bar_state_update") == 0) {
client->subscribed_events |= event_mask(IPC_EVENT_BAR_STATE_UPDATE);
} else if (strcmp(event_type, "mode") == 0) { } else if (strcmp(event_type, "mode") == 0) {
client->subscribed_events |= event_mask(IPC_EVENT_MODE); client->subscribed_events |= event_mask(IPC_EVENT_MODE);
} else if (strcmp(event_type, "shutdown") == 0) { } else if (strcmp(event_type, "shutdown") == 0) {

View file

@ -65,6 +65,22 @@ Sway allows configuring swaybar in the sway configuration file.
is given, when mouse button _n_ has been released). To disable the default is given, when mouse button _n_ has been released). To disable the default
behavior for a button, use the command _nop_. behavior for a button, use the command _nop_.
*mode* dock|hide|invisible
Specifies the visibility of the bar. In _dock_ mode, it is permanently
visible at one edge of the screen. In _hide_ mode, it is hidden unless the
modifier key is pressed, though this behaviour depends on the hidden state.
In _invisible_ mode, it is permanently hidden. Default is _dock_.
*hidden\_state* hide|show
Specifies the behaviour of the bar when it is in _hide_ mode. When the
hidden state is _hide_, then it is normally hidden, and only unhidden by
pressing the modifier key or in case of urgency hints. When the hidden
state is _show_, then it is permanently visible, drawn on top of the
currently visible workspace. Default is _hide_.
*modifier* <Modifier>|none
Specifies the modifier key that shows a hidden bar. Default is _Mod4_.
## TRAY ## TRAY
Swaybar provides a system tray where third-party applications may place icons. Swaybar provides a system tray where third-party applications may place icons.

View file

@ -614,6 +614,18 @@ match any output by using the output name "\*".
*workspace\_layout* default|stacking|tabbed *workspace\_layout* default|stacking|tabbed
Specifies the initial layout for new workspaces. Specifies the initial layout for new workspaces.
# BAR CONTROL
*bar hidden\_state* hide|show|toggle [<bar\_id>]
Sets the hidden state of the bar (see *sway-bar*(5)), either individually,
by specifying a bar id, or if none is given, for all bar instances.
_toggle_ switches between _hide_ and _show_.
*bar mode* dock|hide|invisible|toggle [<bar\_id>]
Sets the mode of the bar (see *sway-bar*(5)), either individually,
by specifying a bar id, or if none is given, for all bar instances.
_toggle_ switches between _dock_ and _hide_.
# CRITERIA # CRITERIA
A criteria is a string in the form of, for example: A criteria is a string in the form of, for example:

View file

@ -32,9 +32,21 @@
static void bar_init(struct swaybar *bar) { static void bar_init(struct swaybar *bar) {
bar->config = init_config(); bar->config = init_config();
bar->visible = true;
wl_list_init(&bar->outputs); wl_list_init(&bar->outputs);
} }
void free_hotspots(struct wl_list *list) {
struct swaybar_hotspot *hotspot, *tmp;
wl_list_for_each_safe(hotspot, tmp, list, link) {
wl_list_remove(&hotspot->link);
if (hotspot->destroy) {
hotspot->destroy(hotspot->data);
}
free(hotspot);
}
}
void free_workspaces(struct wl_list *list) { void free_workspaces(struct wl_list *list) {
struct swaybar_workspace *ws, *tmp; struct swaybar_workspace *ws, *tmp;
wl_list_for_each_safe(ws, tmp, list, link) { wl_list_for_each_safe(ws, tmp, list, link) {
@ -59,14 +71,8 @@ static void swaybar_output_free(struct swaybar_output *output) {
wl_output_destroy(output->output); wl_output_destroy(output->output);
destroy_buffer(&output->buffers[0]); destroy_buffer(&output->buffers[0]);
destroy_buffer(&output->buffers[1]); destroy_buffer(&output->buffers[1]);
free_hotspots(&output->hotspots);
free_workspaces(&output->workspaces); free_workspaces(&output->workspaces);
struct swaybar_hotspot *hotspot, *hotspot_tmp;
wl_list_for_each_safe(hotspot, hotspot_tmp, &output->hotspots, link) {
if (hotspot->destroy) {
hotspot->destroy(hotspot->data);
}
free(hotspot);
}
wl_list_remove(&output->link); wl_list_remove(&output->link);
free(output->name); free(output->name);
free(output); free(output);
@ -75,9 +81,7 @@ static void swaybar_output_free(struct swaybar_output *output) {
static void set_output_dirty(struct swaybar_output *output) { static void set_output_dirty(struct swaybar_output *output) {
if (output->frame_scheduled) { if (output->frame_scheduled) {
output->dirty = true; output->dirty = true;
return; } else if (output->surface) {
}
if (output->surface) {
render_frame(output); render_frame(output);
} }
} }
@ -335,21 +339,68 @@ const struct wl_seat_listener seat_listener = {
}; };
static void add_layer_surface(struct swaybar_output *output) { static void add_layer_surface(struct swaybar_output *output) {
if (output->surface != NULL) { if (output->layer_surface) {
return; return;
} }
struct swaybar *bar = output->bar; struct swaybar *bar = output->bar;
output->surface = wl_compositor_create_surface(bar->compositor); struct swaybar_config *config = bar->config;
assert(output->surface); bool hidden = strcmp(config->mode, "hide") == 0;
output->layer_surface = zwlr_layer_shell_v1_get_layer_surface( output->layer_surface = zwlr_layer_shell_v1_get_layer_surface(
bar->layer_shell, output->surface, output->output, bar->layer_shell, output->surface, output->output,
hidden ? ZWLR_LAYER_SHELL_V1_LAYER_TOP :
ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM, "panel"); ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM, "panel");
assert(output->layer_surface); assert(output->layer_surface);
zwlr_layer_surface_v1_add_listener(output->layer_surface, zwlr_layer_surface_v1_add_listener(output->layer_surface,
&layer_surface_listener, output); &layer_surface_listener, output);
zwlr_layer_surface_v1_set_anchor(output->layer_surface,
bar->config->position); zwlr_layer_surface_v1_set_anchor(output->layer_surface, config->position);
if (hidden) {
zwlr_layer_surface_v1_set_exclusive_zone(output->layer_surface, -1);
}
}
static void destroy_layer_surface(struct swaybar_output *output) {
if (!output->layer_surface) {
return;
}
zwlr_layer_surface_v1_destroy(output->layer_surface);
wl_surface_attach(output->surface, NULL, 0, 0); // detach buffer
output->layer_surface = NULL;
output->width = 0;
output->frame_scheduled = false;
}
bool determine_bar_visibility(struct swaybar *bar, bool moving_layer) {
struct swaybar_config *config = bar->config;
bool visible = !(strcmp(config->mode, "invisible") == 0 ||
(strcmp(config->mode, config->hidden_state) == 0 // both "hide"
&& !bar->visible_by_modifier && !bar->visible_by_urgency));
struct swaybar_output *output;
if (visible == bar->visible) {
if (visible && moving_layer) {
// need to destroy layer surface to move to a different layer
wl_list_for_each(output, &bar->outputs, link) {
destroy_layer_surface(output);
add_layer_surface(output);
}
}
} else {
bar->visible = visible;
wl_list_for_each(output, &bar->outputs, link) {
if (visible) {
add_layer_surface(output);
} else {
destroy_layer_surface(output);
}
}
wlr_log(WLR_DEBUG, "Sending %s signal to status command",
visible ? "cont" : "stop");
kill(bar->status->pid,
visible ? bar->status->cont_signal : bar->status->stop_signal);
}
return visible;
} }
static bool bar_uses_output(struct swaybar *bar, const char *name) { static bool bar_uses_output(struct swaybar *bar, const char *name) {
@ -420,8 +471,11 @@ static void xdg_output_handle_done(void *data,
wl_list_remove(&output->link); wl_list_remove(&output->link);
wl_list_insert(&bar->outputs, &output->link); wl_list_insert(&bar->outputs, &output->link);
add_layer_surface(output); output->surface = wl_compositor_create_surface(bar->compositor);
set_output_dirty(output); assert(output->surface);
if (bar->visible) {
add_layer_surface(output);
}
} }
} }
@ -517,14 +571,13 @@ static void set_bar_dirty(struct swaybar *bar) {
} }
} }
bool bar_setup(struct swaybar *bar, bool bar_setup(struct swaybar *bar, const char *socket_path) {
const char *socket_path, const char *bar_id) {
bar_init(bar); bar_init(bar);
init_event_loop(); init_event_loop();
bar->ipc_socketfd = ipc_open_socket(socket_path); bar->ipc_socketfd = ipc_open_socket(socket_path);
bar->ipc_event_socketfd = ipc_open_socket(socket_path); bar->ipc_event_socketfd = ipc_open_socket(socket_path);
if (!ipc_initialize(bar, bar_id)) { if (!ipc_initialize(bar)) {
return false; return false;
} }
if (bar->config->status_command) { if (bar->config->status_command) {
@ -565,8 +618,11 @@ bool bar_setup(struct swaybar *bar,
pointer->cursor_surface = wl_compositor_create_surface(bar->compositor); pointer->cursor_surface = wl_compositor_create_surface(bar->compositor);
assert(pointer->cursor_surface); assert(pointer->cursor_surface);
ipc_get_workspaces(bar); if (bar->config->workspace_buttons) {
set_bar_dirty(bar); if (ipc_get_workspaces(bar)) {
set_bar_dirty(bar);
}
}
return true; return true;
} }
@ -625,4 +681,6 @@ void bar_teardown(struct swaybar *bar) {
if (bar->status) { if (bar->status) {
status_line_free(bar->status); status_line_free(bar->status);
} }
free(bar->id);
free(bar->mode);
} }

View file

@ -30,7 +30,8 @@ struct swaybar_config *init_config(void) {
config->pango_markup = false; config->pango_markup = false;
config->position = parse_position("bottom"); config->position = parse_position("bottom");
config->font = strdup("monospace 10"); config->font = strdup("monospace 10");
config->mode = NULL; config->mode = strdup("dock");
config->hidden_state = strdup("hide");
config->sep_symbol = NULL; config->sep_symbol = NULL;
config->strip_workspace_numbers = false; config->strip_workspace_numbers = false;
config->binding_mode_indicator = true; config->binding_mode_indicator = true;
@ -84,6 +85,7 @@ void free_config(struct swaybar_config *config) {
free(config->status_command); free(config->status_command);
free(config->font); free(config->font);
free(config->mode); free(config->mode);
free(config->hidden_state);
free(config->sep_symbol); free(config->sep_symbol);
for (int i = 0; i < config->bindings->length; i++) { for (int i = 0; i < config->bindings->length; i++) {
struct swaybar_binding *binding = config->bindings->items[i]; struct swaybar_binding *binding = config->bindings->items[i];

View file

@ -152,12 +152,12 @@ static bool ipc_parse_config(
json_object_put(bar_config); json_object_put(bar_config);
return false; return false;
} }
json_object *markup, *mode, *hidden_bar, *position, *status_command; json_object *markup, *mode, *hidden_state, *position, *status_command;
json_object *font, *bar_height, *wrap_scroll, *workspace_buttons, *strip_workspace_numbers; json_object *font, *bar_height, *wrap_scroll, *workspace_buttons, *strip_workspace_numbers;
json_object *binding_mode_indicator, *verbose, *colors, *sep_symbol, *outputs; json_object *binding_mode_indicator, *verbose, *colors, *sep_symbol, *outputs;
json_object *bindings; json_object *bindings;
json_object_object_get_ex(bar_config, "mode", &mode); json_object_object_get_ex(bar_config, "mode", &mode);
json_object_object_get_ex(bar_config, "hidden_bar", &hidden_bar); json_object_object_get_ex(bar_config, "hidden_state", &hidden_state);
json_object_object_get_ex(bar_config, "position", &position); json_object_object_get_ex(bar_config, "position", &position);
json_object_object_get_ex(bar_config, "status_command", &status_command); json_object_object_get_ex(bar_config, "status_command", &status_command);
json_object_object_get_ex(bar_config, "font", &font); json_object_object_get_ex(bar_config, "font", &font);
@ -220,6 +220,14 @@ static bool ipc_parse_config(
list_add(config->bindings, binding); list_add(config->bindings, binding);
} }
} }
if (hidden_state) {
free(config->hidden_state);
config->hidden_state = strdup(json_object_get_string(hidden_state));
}
if (mode) {
free(config->mode);
config->mode = strdup(json_object_get_string(mode));
}
struct config_output *output, *tmp; struct config_output *output, *tmp;
wl_list_for_each_safe(output, tmp, &config->outputs, link) { wl_list_for_each_safe(output, tmp, &config->outputs, link) {
@ -254,7 +262,7 @@ static bool ipc_parse_config(
return true; return true;
} }
void ipc_get_workspaces(struct swaybar *bar) { bool ipc_get_workspaces(struct swaybar *bar) {
struct swaybar_output *output; struct swaybar_output *output;
wl_list_for_each(output, &bar->outputs, link) { wl_list_for_each(output, &bar->outputs, link) {
free_workspaces(&output->workspaces); free_workspaces(&output->workspaces);
@ -266,8 +274,10 @@ void ipc_get_workspaces(struct swaybar *bar) {
json_object *results = json_tokener_parse(res); json_object *results = json_tokener_parse(res);
if (!results) { if (!results) {
free(res); free(res);
return; return false;
} }
bar->visible_by_urgency = false;
size_t length = json_object_array_length(results); size_t length = json_object_array_length(results);
json_object *ws_json; json_object *ws_json;
json_object *num, *name, *visible, *focused, *out, *urgent; json_object *num, *name, *visible, *focused, *out, *urgent;
@ -294,12 +304,16 @@ void ipc_get_workspaces(struct swaybar *bar) {
output->focused = true; output->focused = true;
} }
ws->urgent = json_object_get_boolean(urgent); ws->urgent = json_object_get_boolean(urgent);
if (ws->urgent) {
bar->visible_by_urgency = true;
}
wl_list_insert(&output->workspaces, &ws->link); wl_list_insert(&output->workspaces, &ws->link);
} }
} }
} }
json_object_put(results); json_object_put(results);
free(res); free(res);
return determine_bar_visibility(bar, false);
} }
static void ipc_get_outputs(struct swaybar *bar) { static void ipc_get_outputs(struct swaybar *bar) {
@ -345,10 +359,10 @@ void ipc_execute_binding(struct swaybar *bar, struct swaybar_binding *bind) {
IPC_COMMAND, bind->command, &len)); IPC_COMMAND, bind->command, &len));
} }
bool ipc_initialize(struct swaybar *bar, const char *bar_id) { bool ipc_initialize(struct swaybar *bar) {
uint32_t len = strlen(bar_id); uint32_t len = strlen(bar->id);
char *res = ipc_single_command(bar->ipc_socketfd, char *res = ipc_single_command(bar->ipc_socketfd,
IPC_GET_BAR_CONFIG, bar_id, &len); IPC_GET_BAR_CONFIG, bar->id, &len);
if (!ipc_parse_config(bar->config, res)) { if (!ipc_parse_config(bar->config, res)) {
free(res); free(res);
return false; return false;
@ -356,56 +370,108 @@ bool ipc_initialize(struct swaybar *bar, const char *bar_id) {
free(res); free(res);
ipc_get_outputs(bar); ipc_get_outputs(bar);
const char *subscribe = "[ \"workspace\", \"mode\" ]"; struct swaybar_config *config = bar->config;
len = strlen(subscribe); char subscribe[128]; // suitably large buffer
len = snprintf(subscribe, 128,
"[ \"barconfig_update\" , \"bar_state_update\" %s %s ]",
config->binding_mode_indicator ? ", \"mode\"" : "",
config->workspace_buttons ? ", \"workspace\"" : "");
free(ipc_single_command(bar->ipc_event_socketfd, free(ipc_single_command(bar->ipc_event_socketfd,
IPC_SUBSCRIBE, subscribe, &len)); IPC_SUBSCRIBE, subscribe, &len));
return true; return true;
} }
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);
return determine_bar_visibility(bar, false);
}
static bool handle_barconfig_update(struct swaybar *bar,
json_object *json_config) {
json_object *json_id;
json_object_object_get_ex(json_config, "id", &json_id);
const char *id = json_object_get_string(json_id);
if (strcmp(id, bar->id) != 0) {
return false;
}
struct swaybar_config *config = bar->config;
json_object *json_state;
json_object_object_get_ex(json_config, "hidden_state", &json_state);
const char *new_state = json_object_get_string(json_state);
char *old_state = config->hidden_state;
if (strcmp(new_state, old_state) != 0) {
wlr_log(WLR_DEBUG, "Changing bar hidden state to %s", new_state);
free(old_state);
config->hidden_state = strdup(new_state);
return determine_bar_visibility(bar, false);
}
free(config->mode);
json_object *json_mode;
json_object_object_get_ex(json_config, "mode", &json_mode);
config->mode = strdup(json_object_get_string(json_mode));
wlr_log(WLR_DEBUG, "Changing bar mode to %s", config->mode);
return determine_bar_visibility(bar, true);
}
bool handle_ipc_readable(struct swaybar *bar) { bool handle_ipc_readable(struct swaybar *bar) {
struct ipc_response *resp = ipc_recv_response(bar->ipc_event_socketfd); struct ipc_response *resp = ipc_recv_response(bar->ipc_event_socketfd);
if (!resp) { if (!resp) {
return false; return false;
} }
switch (resp->type) {
case IPC_EVENT_WORKSPACE: json_object *result = json_tokener_parse(resp->payload);
ipc_get_workspaces(bar); if (!result) {
break; wlr_log(WLR_ERROR, "failed to parse payload as json");
case IPC_EVENT_MODE: {
json_object *result = json_tokener_parse(resp->payload);
if (!result) {
free_ipc_response(resp);
wlr_log(WLR_ERROR, "failed to parse payload as json");
return false;
}
json_object *json_change, *json_pango_markup;
if (json_object_object_get_ex(result, "change", &json_change)) {
const char *change = json_object_get_string(json_change);
free(bar->config->mode);
if (strcmp(change, "default") == 0) {
bar->config->mode = NULL;
} else {
bar->config->mode = strdup(change);
}
} else {
wlr_log(WLR_ERROR, "failed to parse response");
json_object_put(result);
free_ipc_response(resp);
return false;
}
if (json_object_object_get_ex(result,
"pango_markup", &json_pango_markup)) {
bar->config->mode_pango_markup = json_object_get_boolean(
json_pango_markup);
}
json_object_put(result);
break;
}
default:
free_ipc_response(resp); free_ipc_response(resp);
return false; return false;
} }
bool bar_is_dirty = true;
switch (resp->type) {
case IPC_EVENT_WORKSPACE:
bar_is_dirty = ipc_get_workspaces(bar);
break;
case IPC_EVENT_MODE: {
json_object *json_change, *json_pango_markup;
if (json_object_object_get_ex(result, "change", &json_change)) {
const char *change = json_object_get_string(json_change);
free(bar->mode);
bar->mode = strcmp(change, "default") != 0 ? strdup(change) : NULL;
} else {
wlr_log(WLR_ERROR, "failed to parse response");
bar_is_dirty = false;
break;
}
if (json_object_object_get_ex(result,
"pango_markup", &json_pango_markup)) {
bar->mode_pango_markup = json_object_get_boolean(json_pango_markup);
}
break;
}
case IPC_EVENT_BARCONFIG_UPDATE:
bar_is_dirty = handle_barconfig_update(bar, result);
break;
case IPC_EVENT_BAR_STATE_UPDATE:
bar_is_dirty = handle_bar_state_update(bar, result);
break;
default:
bar_is_dirty = false;
break;
}
json_object_put(result);
free_ipc_response(resp); free_ipc_response(resp);
return true; return bar_is_dirty;
} }

View file

@ -22,7 +22,6 @@ void sway_terminate(int code) {
int main(int argc, char **argv) { int main(int argc, char **argv) {
char *socket_path = NULL; char *socket_path = NULL;
char *bar_id = NULL;
bool debug = false; bool debug = false;
static struct option long_options[] = { static struct option long_options[] = {
@ -59,7 +58,7 @@ int main(int argc, char **argv) {
socket_path = strdup(optarg); socket_path = strdup(optarg);
break; break;
case 'b': // Type case 'b': // Type
bar_id = strdup(optarg); swaybar.id = strdup(optarg);
break; break;
case 'v': case 'v':
fprintf(stdout, "swaybar version " SWAY_VERSION "\n"); fprintf(stdout, "swaybar version " SWAY_VERSION "\n");
@ -80,7 +79,7 @@ int main(int argc, char **argv) {
wlr_log_init(WLR_ERROR, NULL); wlr_log_init(WLR_ERROR, NULL);
} }
if (!bar_id) { if (!swaybar.id) {
wlr_log(WLR_ERROR, "No bar_id passed. " wlr_log(WLR_ERROR, "No bar_id passed. "
"Provide --bar_id or let sway start swaybar"); "Provide --bar_id or let sway start swaybar");
return 1; return 1;
@ -96,13 +95,12 @@ int main(int argc, char **argv) {
signal(SIGTERM, sig_handler); signal(SIGTERM, sig_handler);
if (!bar_setup(&swaybar, socket_path, bar_id)) { if (!bar_setup(&swaybar, socket_path)) {
free(socket_path); free(socket_path);
return 1; return 1;
} }
free(socket_path); free(socket_path);
free(bar_id);
bar_run(&swaybar); bar_run(&swaybar);
bar_teardown(&swaybar); bar_teardown(&swaybar);

View file

@ -296,11 +296,15 @@ static uint32_t render_status_line(cairo_t *cairo,
static uint32_t render_binding_mode_indicator(cairo_t *cairo, static uint32_t render_binding_mode_indicator(cairo_t *cairo,
struct swaybar_output *output, double x) { struct swaybar_output *output, double x) {
const char *mode = output->bar->mode;
if (!mode) {
return 0;
}
struct swaybar_config *config = output->bar->config; struct swaybar_config *config = output->bar->config;
const char *mode = config->mode;
int text_width, text_height; int text_width, text_height;
get_text_size(cairo, config->font, &text_width, &text_height, NULL, get_text_size(cairo, config->font, &text_width, &text_height, NULL,
output->scale, config->mode_pango_markup, output->scale, output->bar->mode_pango_markup,
"%s", mode); "%s", mode);
int ws_vertical_padding = WS_VERTICAL_PADDING * output->scale; int ws_vertical_padding = WS_VERTICAL_PADDING * output->scale;
@ -333,8 +337,8 @@ static uint32_t render_binding_mode_indicator(cairo_t *cairo,
double text_y = height / 2.0 - text_height / 2.0; double text_y = height / 2.0 - text_height / 2.0;
cairo_set_source_u32(cairo, config->colors.binding_mode.text); cairo_set_source_u32(cairo, config->colors.binding_mode.text);
cairo_move_to(cairo, x + width / 2 - text_width / 2, (int)floor(text_y)); cairo_move_to(cairo, x + width / 2 - text_width / 2, (int)floor(text_y));
pango_printf(cairo, config->font, output->scale, config->mode_pango_markup, pango_printf(cairo, config->font, output->scale,
"%s", mode); output->bar->mode_pango_markup, "%s", mode);
return output->height; return output->height;
} }
@ -465,7 +469,7 @@ static uint32_t render_to_cairo(cairo_t *cairo, struct swaybar_output *output) {
max_height = h > max_height ? h : max_height; max_height = h > max_height ? h : max_height;
} }
} }
if (config->binding_mode_indicator && config->mode) { if (config->binding_mode_indicator) {
uint32_t h = render_binding_mode_indicator(cairo, output, x); uint32_t h = render_binding_mode_indicator(cairo, output, x);
max_height = h > max_height ? h : max_height; max_height = h > max_height ? h : max_height;
} }
@ -490,16 +494,12 @@ static const struct wl_callback_listener output_frame_listener = {
void render_frame(struct swaybar_output *output) { void render_frame(struct swaybar_output *output) {
assert(output->surface != NULL); assert(output->surface != NULL);
if (!output->layer_surface) {
struct swaybar_hotspot *hotspot, *tmp; return;
wl_list_for_each_safe(hotspot, tmp, &output->hotspots, link) {
if (hotspot->destroy) {
hotspot->destroy(hotspot->data);
}
wl_list_remove(&hotspot->link);
free(hotspot);
} }
free_hotspots(&output->hotspots);
cairo_surface_t *recorder = cairo_recording_surface_create( cairo_surface_t *recorder = cairo_recording_surface_create(
CAIRO_CONTENT_COLOR_ALPHA, NULL); CAIRO_CONTENT_COLOR_ALPHA, NULL);
cairo_t *cairo = cairo_create(recorder); cairo_t *cairo = cairo_create(recorder);
@ -519,10 +519,12 @@ void render_frame(struct swaybar_output *output) {
if (config_height >= 0 && height < (uint32_t)config_height) { if (config_height >= 0 && height < (uint32_t)config_height) {
height = config_height; height = config_height;
} }
if (height != output->height) { if (height != output->height || output->width == 0) {
// Reconfigure surface // Reconfigure surface
zwlr_layer_surface_v1_set_size(output->layer_surface, 0, height); zwlr_layer_surface_v1_set_size(output->layer_surface, 0, height);
zwlr_layer_surface_v1_set_exclusive_zone(output->layer_surface, height); if (strcmp(output->bar->config->mode, "dock") == 0) {
zwlr_layer_surface_v1_set_exclusive_zone(output->layer_surface, height);
}
// TODO: this could infinite loop if the compositor assigns us a // TODO: this could infinite loop if the compositor assigns us a
// different height than what we asked for // different height than what we asked for
wl_surface_commit(output->surface); wl_surface_commit(output->surface);

View file

@ -83,6 +83,17 @@ bool status_handle_readable(struct status_line *status) {
return true; return true;
} }
} }
json_object *signal;
if (json_object_object_get_ex(header, "stop_signal", &signal)) {
status->stop_signal = json_object_get_int(signal);
wlr_log(WLR_DEBUG, "Setting stop signal to %d", status->stop_signal);
}
if (json_object_object_get_ex(header, "cont_signal", &signal)) {
status->cont_signal = json_object_get_int(signal);
wlr_log(WLR_DEBUG, "Setting cont signal to %d", status->cont_signal);
}
json_object_put(header); json_object_put(header);
wl_list_init(&status->blocks); wl_list_init(&status->blocks);
@ -121,6 +132,9 @@ bool status_handle_readable(struct status_line *status) {
struct status_line *status_line_init(char *cmd) { struct status_line *status_line_init(char *cmd) {
struct status_line *status = calloc(1, sizeof(struct status_line)); struct status_line *status = calloc(1, sizeof(struct status_line));
status->stop_signal = SIGSTOP;
status->cont_signal = SIGCONT;
status->buffer_size = 8192; status->buffer_size = 8192;
status->buffer = malloc(status->buffer_size); status->buffer = malloc(status->buffer_size);