mirror of
https://github.com/swaywm/sway.git
synced 2024-12-28 07:56:31 +01:00
Merge pull request #2751 from ianyfan/swaybar
Bar mode/hidden_state events
This commit is contained in:
commit
4a05fbf8ab
21 changed files with 372 additions and 144 deletions
|
@ -30,6 +30,9 @@ enum ipc_command_type {
|
|||
IPC_EVENT_BINDING = ((1<<31) | 5),
|
||||
IPC_EVENT_SHUTDOWN = ((1<<31) | 6),
|
||||
IPC_EVENT_TICK = ((1<<31) | 7),
|
||||
|
||||
// sway-specific event types
|
||||
IPC_EVENT_BAR_STATE_UPDATE = ((1<<31) | 20),
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -191,6 +191,7 @@ struct bar_config {
|
|||
* In "show" mode, it will always be shown on top of the active workspace.
|
||||
*/
|
||||
char *hidden_state;
|
||||
bool visible_by_modifier; // only relevant in "hide" mode
|
||||
/**
|
||||
* Id name used to identify the bar through IPC.
|
||||
*
|
||||
|
|
|
@ -15,6 +15,7 @@ void ipc_event_workspace(struct sway_workspace *old,
|
|||
struct sway_workspace *new, 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_bar_state_update(struct bar_config *bar);
|
||||
void ipc_event_mode(const char *mode, bool pango);
|
||||
void ipc_event_shutdown(const char *reason);
|
||||
void ipc_event_binding(struct sway_binding *binding);
|
||||
|
|
|
@ -37,7 +37,7 @@ enum hotspot_event_handling {
|
|||
};
|
||||
|
||||
struct swaybar_hotspot {
|
||||
struct wl_list link;
|
||||
struct wl_list link; // swaybar_output::hotspots
|
||||
int x, y, width, height;
|
||||
enum hotspot_event_handling (*callback)(struct swaybar_output *output,
|
||||
int x, int y, enum x11_button button, void *data);
|
||||
|
@ -46,6 +46,15 @@ struct swaybar_hotspot {
|
|||
};
|
||||
|
||||
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_compositor *compositor;
|
||||
struct zwlr_layer_shell_v1 *layer_shell;
|
||||
|
@ -60,11 +69,11 @@ struct swaybar {
|
|||
int ipc_event_socketfd;
|
||||
int ipc_socketfd;
|
||||
|
||||
struct wl_list outputs;
|
||||
struct wl_list outputs; // swaybar_output::link
|
||||
};
|
||||
|
||||
struct swaybar_output {
|
||||
struct wl_list link;
|
||||
struct wl_list link; // swaybar::outputs
|
||||
struct swaybar *bar;
|
||||
struct wl_output *output;
|
||||
struct zxdg_output_v1 *xdg_output;
|
||||
|
@ -72,8 +81,8 @@ struct swaybar_output {
|
|||
struct zwlr_layer_surface_v1 *layer_surface;
|
||||
uint32_t wl_name;
|
||||
|
||||
struct wl_list workspaces;
|
||||
struct wl_list hotspots;
|
||||
struct wl_list workspaces; // swaybar_workspace::link
|
||||
struct wl_list hotspots; // swaybar_hotspot::link
|
||||
|
||||
char *name;
|
||||
bool focused;
|
||||
|
@ -88,7 +97,7 @@ struct swaybar_output {
|
|||
};
|
||||
|
||||
struct swaybar_workspace {
|
||||
struct wl_list link;
|
||||
struct wl_list link; // swaybar_output::workspaces
|
||||
int num;
|
||||
char *name;
|
||||
bool focused;
|
||||
|
@ -96,10 +105,24 @@ struct swaybar_workspace {
|
|||
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_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);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -13,7 +13,7 @@ struct box_colors {
|
|||
};
|
||||
|
||||
struct config_output {
|
||||
struct wl_list link;
|
||||
struct wl_list link; // swaybar_config::outputs
|
||||
char *name;
|
||||
size_t index;
|
||||
};
|
||||
|
@ -31,7 +31,8 @@ struct swaybar_config {
|
|||
char *font;
|
||||
char *sep_symbol;
|
||||
char *mode;
|
||||
bool mode_pango_markup;
|
||||
char *hidden_state;
|
||||
char *modifier;
|
||||
bool strip_workspace_numbers;
|
||||
bool binding_mode_indicator;
|
||||
bool wrap_scroll;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include "status_line.h"
|
||||
|
||||
struct i3bar_block {
|
||||
struct wl_list link;
|
||||
struct wl_list link; // status_link::blocks
|
||||
int ref_count;
|
||||
char *full_text, *short_text, *align;
|
||||
bool urgent;
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
#include <stdbool.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);
|
||||
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_execute_binding(struct swaybar *bar, struct swaybar_binding *bind);
|
||||
|
||||
|
|
|
@ -22,6 +22,9 @@ struct status_line {
|
|||
const char *text;
|
||||
struct wl_list blocks; // i3bar_block::link
|
||||
|
||||
int stop_signal;
|
||||
int cont_signal;
|
||||
|
||||
bool click_events;
|
||||
bool clicked;
|
||||
char *buffer;
|
||||
|
|
|
@ -32,7 +32,7 @@ static struct cmd_results *bar_set_hidden_state(struct bar_config *bar,
|
|||
}
|
||||
// free old mode
|
||||
free(old_state);
|
||||
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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];
|
||||
if (config->reading) {
|
||||
return bar_set_hidden_state(config->current_bar, state);
|
||||
}
|
||||
|
||||
const char *id = NULL;
|
||||
if (argc == 2) {
|
||||
id = argv[1];
|
||||
}
|
||||
struct bar_config *bar;
|
||||
for (int i = 0; i < config->bars->length; ++i) {
|
||||
bar = config->bars->items[i];
|
||||
if (id && strcmp(id, bar->id) == 0) {
|
||||
return bar_set_hidden_state(bar, state);
|
||||
}
|
||||
|
||||
error = bar_set_hidden_state(bar, state);
|
||||
if (error) {
|
||||
return error;
|
||||
error = bar_set_hidden_state(config->current_bar, state);
|
||||
} else {
|
||||
const char *id = argc == 2 ? argv[1] : NULL;
|
||||
for (int i = 0; i < config->bars->length; ++i) {
|
||||
struct bar_config *bar = config->bars->items[i];
|
||||
if (id) {
|
||||
if (strcmp(id, bar->id) == 0) {
|
||||
error = bar_set_hidden_state(bar, state);
|
||||
break;
|
||||
}
|
||||
} else if ((error = bar_set_hidden_state(bar, state))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
||||
return error ? error : cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ static struct cmd_results *bar_set_mode(struct bar_config *bar, const char *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) {
|
||||
|
@ -51,24 +51,20 @@ struct cmd_results *bar_cmd_mode(int argc, char **argv) {
|
|||
|
||||
const char *mode = argv[0];
|
||||
if (config->reading) {
|
||||
return bar_set_mode(config->current_bar, mode);
|
||||
}
|
||||
|
||||
const char *id = NULL;
|
||||
if (argc == 2) {
|
||||
id = argv[1];
|
||||
}
|
||||
|
||||
struct bar_config *bar;
|
||||
for (int i = 0; i < config->bars->length; ++i) {
|
||||
bar = config->bars->items[i];
|
||||
if (id && strcmp(id, bar->id) == 0) {
|
||||
return bar_set_mode(bar, mode);
|
||||
}
|
||||
error = bar_set_mode(bar, mode);
|
||||
if (error) {
|
||||
return error;
|
||||
error = bar_set_mode(config->current_bar, mode);
|
||||
} else {
|
||||
const char *id = argc == 2 ? argv[1] : NULL;
|
||||
for (int i = 0; i < config->bars->length; ++i) {
|
||||
struct bar_config *bar = config->bars->items[i];
|
||||
if (id) {
|
||||
if (strcmp(id, bar->id) == 0) {
|
||||
error = bar_set_mode(bar, mode);
|
||||
break;
|
||||
}
|
||||
} else if ((error = bar_set_mode(bar, mode))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
||||
return error ? error : cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "stringop.h"
|
||||
#include "list.h"
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
|
||||
static void terminate_swaybar(pid_t 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->verbose = false;
|
||||
bar->pid = 0;
|
||||
bar->modifier = get_modifier_mask_by_name("Mod4");
|
||||
if (!(bar->mode = strdup("dock"))) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "sway/input/input-manager.h"
|
||||
#include "sway/input/keyboard.h"
|
||||
#include "sway/input/seat.h"
|
||||
#include "sway/ipc-server.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;
|
||||
state->last_raw_modifiers = raw_modifiers;
|
||||
|
||||
if (last_key_was_a_modifier && state->last_keycode) {
|
||||
// Last pressed key before this one was a modifier
|
||||
state_erase_key(state, state->last_keycode);
|
||||
}
|
||||
if (last_key_was_a_modifier && state->last_keycode) {
|
||||
// Last pressed key before this one was a modifier
|
||||
state_erase_key(state, state->last_keycode);
|
||||
}
|
||||
|
||||
if (event->state == WLR_KEY_PRESSED) {
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
||||
bool handled = false;
|
||||
|
||||
// Identify active release binding
|
||||
|
@ -337,6 +337,19 @@ static int handle_keyboard_repeat(void *data) {
|
|||
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,
|
||||
void *data) {
|
||||
struct sway_keyboard *keyboard =
|
||||
|
@ -346,6 +359,9 @@ static void handle_keyboard_modifiers(struct wl_listener *listener,
|
|||
keyboard->seat_device->input_device->wlr_device;
|
||||
wlr_seat_set_keyboard(wlr_seat, wlr_device);
|
||||
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,
|
||||
|
@ -464,7 +480,7 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) {
|
|||
keyboard->keyboard_key.notify = handle_keyboard_key;
|
||||
|
||||
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.notify = handle_keyboard_modifiers;
|
||||
}
|
||||
|
|
|
@ -349,6 +349,22 @@ void ipc_event_barconfig_update(struct bar_config *bar) {
|
|||
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) {
|
||||
if (!ipc_has_event_listeners(IPC_EVENT_MODE)) {
|
||||
return;
|
||||
|
@ -651,6 +667,8 @@ void ipc_client_handle_command(struct ipc_client *client) {
|
|||
client->subscribed_events |= event_mask(IPC_EVENT_WORKSPACE);
|
||||
} else if (strcmp(event_type, "barconfig_update") == 0) {
|
||||
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) {
|
||||
client->subscribed_events |= event_mask(IPC_EVENT_MODE);
|
||||
} else if (strcmp(event_type, "shutdown") == 0) {
|
||||
|
|
|
@ -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
|
||||
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
|
||||
|
||||
Swaybar provides a system tray where third-party applications may place icons.
|
||||
|
|
|
@ -614,6 +614,18 @@ match any output by using the output name "\*".
|
|||
*workspace\_layout* default|stacking|tabbed
|
||||
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
|
||||
|
||||
A criteria is a string in the form of, for example:
|
||||
|
|
102
swaybar/bar.c
102
swaybar/bar.c
|
@ -32,9 +32,21 @@
|
|||
|
||||
static void bar_init(struct swaybar *bar) {
|
||||
bar->config = init_config();
|
||||
bar->visible = true;
|
||||
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) {
|
||||
struct swaybar_workspace *ws, *tmp;
|
||||
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);
|
||||
destroy_buffer(&output->buffers[0]);
|
||||
destroy_buffer(&output->buffers[1]);
|
||||
free_hotspots(&output->hotspots);
|
||||
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);
|
||||
free(output->name);
|
||||
free(output);
|
||||
|
@ -75,9 +81,7 @@ static void swaybar_output_free(struct swaybar_output *output) {
|
|||
static void set_output_dirty(struct swaybar_output *output) {
|
||||
if (output->frame_scheduled) {
|
||||
output->dirty = true;
|
||||
return;
|
||||
}
|
||||
if (output->surface) {
|
||||
} else if (output->surface) {
|
||||
render_frame(output);
|
||||
}
|
||||
}
|
||||
|
@ -335,21 +339,68 @@ const struct wl_seat_listener seat_listener = {
|
|||
};
|
||||
|
||||
static void add_layer_surface(struct swaybar_output *output) {
|
||||
if (output->surface != NULL) {
|
||||
if (output->layer_surface) {
|
||||
return;
|
||||
}
|
||||
struct swaybar *bar = output->bar;
|
||||
|
||||
output->surface = wl_compositor_create_surface(bar->compositor);
|
||||
assert(output->surface);
|
||||
struct swaybar_config *config = bar->config;
|
||||
bool hidden = strcmp(config->mode, "hide") == 0;
|
||||
output->layer_surface = zwlr_layer_shell_v1_get_layer_surface(
|
||||
bar->layer_shell, output->surface, output->output,
|
||||
hidden ? ZWLR_LAYER_SHELL_V1_LAYER_TOP :
|
||||
ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM, "panel");
|
||||
assert(output->layer_surface);
|
||||
zwlr_layer_surface_v1_add_listener(output->layer_surface,
|
||||
&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) {
|
||||
|
@ -420,8 +471,11 @@ static void xdg_output_handle_done(void *data,
|
|||
wl_list_remove(&output->link);
|
||||
wl_list_insert(&bar->outputs, &output->link);
|
||||
|
||||
add_layer_surface(output);
|
||||
set_output_dirty(output);
|
||||
output->surface = wl_compositor_create_surface(bar->compositor);
|
||||
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,
|
||||
const char *socket_path, const char *bar_id) {
|
||||
bool bar_setup(struct swaybar *bar, const char *socket_path) {
|
||||
bar_init(bar);
|
||||
init_event_loop();
|
||||
|
||||
bar->ipc_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;
|
||||
}
|
||||
if (bar->config->status_command) {
|
||||
|
@ -565,8 +618,11 @@ bool bar_setup(struct swaybar *bar,
|
|||
pointer->cursor_surface = wl_compositor_create_surface(bar->compositor);
|
||||
assert(pointer->cursor_surface);
|
||||
|
||||
ipc_get_workspaces(bar);
|
||||
set_bar_dirty(bar);
|
||||
if (bar->config->workspace_buttons) {
|
||||
if (ipc_get_workspaces(bar)) {
|
||||
set_bar_dirty(bar);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -625,4 +681,6 @@ void bar_teardown(struct swaybar *bar) {
|
|||
if (bar->status) {
|
||||
status_line_free(bar->status);
|
||||
}
|
||||
free(bar->id);
|
||||
free(bar->mode);
|
||||
}
|
||||
|
|
|
@ -30,7 +30,8 @@ struct swaybar_config *init_config(void) {
|
|||
config->pango_markup = false;
|
||||
config->position = parse_position("bottom");
|
||||
config->font = strdup("monospace 10");
|
||||
config->mode = NULL;
|
||||
config->mode = strdup("dock");
|
||||
config->hidden_state = strdup("hide");
|
||||
config->sep_symbol = NULL;
|
||||
config->strip_workspace_numbers = false;
|
||||
config->binding_mode_indicator = true;
|
||||
|
@ -84,6 +85,7 @@ void free_config(struct swaybar_config *config) {
|
|||
free(config->status_command);
|
||||
free(config->font);
|
||||
free(config->mode);
|
||||
free(config->hidden_state);
|
||||
free(config->sep_symbol);
|
||||
for (int i = 0; i < config->bindings->length; i++) {
|
||||
struct swaybar_binding *binding = config->bindings->items[i];
|
||||
|
|
156
swaybar/ipc.c
156
swaybar/ipc.c
|
@ -152,12 +152,12 @@ static bool ipc_parse_config(
|
|||
json_object_put(bar_config);
|
||||
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 *binding_mode_indicator, *verbose, *colors, *sep_symbol, *outputs;
|
||||
json_object *bindings;
|
||||
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, "status_command", &status_command);
|
||||
json_object_object_get_ex(bar_config, "font", &font);
|
||||
|
@ -220,6 +220,14 @@ static bool ipc_parse_config(
|
|||
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;
|
||||
wl_list_for_each_safe(output, tmp, &config->outputs, link) {
|
||||
|
@ -254,7 +262,7 @@ static bool ipc_parse_config(
|
|||
return true;
|
||||
}
|
||||
|
||||
void ipc_get_workspaces(struct swaybar *bar) {
|
||||
bool ipc_get_workspaces(struct swaybar *bar) {
|
||||
struct swaybar_output *output;
|
||||
wl_list_for_each(output, &bar->outputs, link) {
|
||||
free_workspaces(&output->workspaces);
|
||||
|
@ -266,8 +274,10 @@ void ipc_get_workspaces(struct swaybar *bar) {
|
|||
json_object *results = json_tokener_parse(res);
|
||||
if (!results) {
|
||||
free(res);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
bar->visible_by_urgency = false;
|
||||
size_t length = json_object_array_length(results);
|
||||
json_object *ws_json;
|
||||
json_object *num, *name, *visible, *focused, *out, *urgent;
|
||||
|
@ -294,12 +304,16 @@ void ipc_get_workspaces(struct swaybar *bar) {
|
|||
output->focused = true;
|
||||
}
|
||||
ws->urgent = json_object_get_boolean(urgent);
|
||||
if (ws->urgent) {
|
||||
bar->visible_by_urgency = true;
|
||||
}
|
||||
wl_list_insert(&output->workspaces, &ws->link);
|
||||
}
|
||||
}
|
||||
}
|
||||
json_object_put(results);
|
||||
free(res);
|
||||
return determine_bar_visibility(bar, false);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
bool ipc_initialize(struct swaybar *bar, const char *bar_id) {
|
||||
uint32_t len = strlen(bar_id);
|
||||
bool ipc_initialize(struct swaybar *bar) {
|
||||
uint32_t len = strlen(bar->id);
|
||||
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)) {
|
||||
free(res);
|
||||
return false;
|
||||
|
@ -356,56 +370,108 @@ bool ipc_initialize(struct swaybar *bar, const char *bar_id) {
|
|||
free(res);
|
||||
ipc_get_outputs(bar);
|
||||
|
||||
const char *subscribe = "[ \"workspace\", \"mode\" ]";
|
||||
len = strlen(subscribe);
|
||||
struct swaybar_config *config = bar->config;
|
||||
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,
|
||||
IPC_SUBSCRIBE, subscribe, &len));
|
||||
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) {
|
||||
struct ipc_response *resp = ipc_recv_response(bar->ipc_event_socketfd);
|
||||
if (!resp) {
|
||||
return false;
|
||||
}
|
||||
switch (resp->type) {
|
||||
case IPC_EVENT_WORKSPACE:
|
||||
ipc_get_workspaces(bar);
|
||||
break;
|
||||
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:
|
||||
|
||||
json_object *result = json_tokener_parse(resp->payload);
|
||||
if (!result) {
|
||||
wlr_log(WLR_ERROR, "failed to parse payload as json");
|
||||
free_ipc_response(resp);
|
||||
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);
|
||||
return true;
|
||||
return bar_is_dirty;
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ void sway_terminate(int code) {
|
|||
|
||||
int main(int argc, char **argv) {
|
||||
char *socket_path = NULL;
|
||||
char *bar_id = NULL;
|
||||
bool debug = false;
|
||||
|
||||
static struct option long_options[] = {
|
||||
|
@ -59,7 +58,7 @@ int main(int argc, char **argv) {
|
|||
socket_path = strdup(optarg);
|
||||
break;
|
||||
case 'b': // Type
|
||||
bar_id = strdup(optarg);
|
||||
swaybar.id = strdup(optarg);
|
||||
break;
|
||||
case 'v':
|
||||
fprintf(stdout, "swaybar version " SWAY_VERSION "\n");
|
||||
|
@ -80,7 +79,7 @@ int main(int argc, char **argv) {
|
|||
wlr_log_init(WLR_ERROR, NULL);
|
||||
}
|
||||
|
||||
if (!bar_id) {
|
||||
if (!swaybar.id) {
|
||||
wlr_log(WLR_ERROR, "No bar_id passed. "
|
||||
"Provide --bar_id or let sway start swaybar");
|
||||
return 1;
|
||||
|
@ -96,13 +95,12 @@ int main(int argc, char **argv) {
|
|||
|
||||
signal(SIGTERM, sig_handler);
|
||||
|
||||
if (!bar_setup(&swaybar, socket_path, bar_id)) {
|
||||
if (!bar_setup(&swaybar, socket_path)) {
|
||||
free(socket_path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
free(socket_path);
|
||||
free(bar_id);
|
||||
|
||||
bar_run(&swaybar);
|
||||
bar_teardown(&swaybar);
|
||||
|
|
|
@ -296,11 +296,15 @@ static uint32_t render_status_line(cairo_t *cairo,
|
|||
|
||||
static uint32_t render_binding_mode_indicator(cairo_t *cairo,
|
||||
struct swaybar_output *output, double x) {
|
||||
const char *mode = output->bar->mode;
|
||||
if (!mode) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct swaybar_config *config = output->bar->config;
|
||||
const char *mode = config->mode;
|
||||
int text_width, text_height;
|
||||
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);
|
||||
|
||||
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;
|
||||
cairo_set_source_u32(cairo, config->colors.binding_mode.text);
|
||||
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,
|
||||
"%s", mode);
|
||||
pango_printf(cairo, config->font, output->scale,
|
||||
output->bar->mode_pango_markup, "%s", mode);
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (config->binding_mode_indicator && config->mode) {
|
||||
if (config->binding_mode_indicator) {
|
||||
uint32_t h = render_binding_mode_indicator(cairo, output, x);
|
||||
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) {
|
||||
assert(output->surface != NULL);
|
||||
|
||||
struct swaybar_hotspot *hotspot, *tmp;
|
||||
wl_list_for_each_safe(hotspot, tmp, &output->hotspots, link) {
|
||||
if (hotspot->destroy) {
|
||||
hotspot->destroy(hotspot->data);
|
||||
}
|
||||
wl_list_remove(&hotspot->link);
|
||||
free(hotspot);
|
||||
if (!output->layer_surface) {
|
||||
return;
|
||||
}
|
||||
|
||||
free_hotspots(&output->hotspots);
|
||||
|
||||
cairo_surface_t *recorder = cairo_recording_surface_create(
|
||||
CAIRO_CONTENT_COLOR_ALPHA, NULL);
|
||||
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) {
|
||||
height = config_height;
|
||||
}
|
||||
if (height != output->height) {
|
||||
if (height != output->height || output->width == 0) {
|
||||
// Reconfigure surface
|
||||
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
|
||||
// different height than what we asked for
|
||||
wl_surface_commit(output->surface);
|
||||
|
|
|
@ -83,6 +83,17 @@ bool status_handle_readable(struct status_line *status) {
|
|||
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);
|
||||
|
||||
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 = calloc(1, sizeof(struct status_line));
|
||||
status->stop_signal = SIGSTOP;
|
||||
status->cont_signal = SIGCONT;
|
||||
|
||||
status->buffer_size = 8192;
|
||||
status->buffer = malloc(status->buffer_size);
|
||||
|
||||
|
|
Loading…
Reference in a new issue