Optionally add focused window title to the bar

Add a "window_title yes|no" bar command that displays the title of the
focused window on the bar.
This commit is contained in:
Pedro Côrte-Real 2019-08-17 19:38:14 +01:00
parent 8441711990
commit 8a019a83c9
10 changed files with 131 additions and 1 deletions

View file

@ -221,6 +221,7 @@ sway_cmd bar_cmd_tray_padding;
sway_cmd bar_cmd_unbindcode; sway_cmd bar_cmd_unbindcode;
sway_cmd bar_cmd_unbindsym; sway_cmd bar_cmd_unbindsym;
sway_cmd bar_cmd_wrap_scroll; sway_cmd bar_cmd_wrap_scroll;
sway_cmd bar_cmd_window_title;
sway_cmd bar_cmd_workspace_buttons; sway_cmd bar_cmd_workspace_buttons;
sway_cmd bar_colors_cmd_active_workspace; sway_cmd bar_colors_cmd_active_workspace;

View file

@ -271,6 +271,7 @@ struct bar_config {
bool strip_workspace_name; bool strip_workspace_name;
bool binding_mode_indicator; bool binding_mode_indicator;
bool verbose; bool verbose;
bool window_title;
struct side_gaps gaps; struct side_gaps gaps;
int status_padding; int status_padding;
int status_edge_padding; int status_edge_padding;

View file

@ -34,10 +34,12 @@ struct swaybar_config {
char *mode; char *mode;
char *hidden_state; char *hidden_state;
char *modifier; char *modifier;
char *title;
bool strip_workspace_numbers; bool strip_workspace_numbers;
bool strip_workspace_name; bool strip_workspace_name;
bool binding_mode_indicator; bool binding_mode_indicator;
bool wrap_scroll; bool wrap_scroll;
bool window_title;
bool workspace_buttons; bool workspace_buttons;
list_t *bindings; list_t *bindings;
struct wl_list outputs; // config_output::link struct wl_list outputs; // config_output::link
@ -51,6 +53,7 @@ struct swaybar_config {
int bottom; int bottom;
int left; int left;
} gaps; } gaps;
uint64_t window_app_id;
struct { struct {
uint32_t background; uint32_t background;

View file

@ -34,6 +34,7 @@ static struct cmd_handler bar_handlers[] = {
{ "tray_padding", bar_cmd_tray_padding }, { "tray_padding", bar_cmd_tray_padding },
{ "unbindcode", bar_cmd_unbindcode }, { "unbindcode", bar_cmd_unbindcode },
{ "unbindsym", bar_cmd_unbindsym }, { "unbindsym", bar_cmd_unbindsym },
{ "window_title", bar_cmd_window_title },
{ "workspace_buttons", bar_cmd_workspace_buttons }, { "workspace_buttons", bar_cmd_workspace_buttons },
{ "wrap_scroll", bar_cmd_wrap_scroll }, { "wrap_scroll", bar_cmd_wrap_scroll },
}; };

View file

@ -0,0 +1,22 @@
#include <string.h>
#include <strings.h>
#include "sway/commands.h"
#include "log.h"
#include "util.h"
struct cmd_results *bar_cmd_window_title(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "window_title", EXPECTED_EQUAL_TO, 1))) {
return error;
}
config->current_bar->window_title =
parse_boolean(argv[0], config->current_bar->window_title);
if (config->current_bar->window_title) {
sway_log(SWAY_DEBUG, "Enabling window title on bar: %s",
config->current_bar->id);
} else {
sway_log(SWAY_DEBUG, "Disabling window title on bar: %s",
config->current_bar->id);
}
return cmd_results_new(CMD_SUCCESS, NULL);
}

View file

@ -958,6 +958,8 @@ json_object *ipc_json_describe_bar_config(struct bar_config *bar) {
json_object_new_int(bar->status_edge_padding)); json_object_new_int(bar->status_edge_padding));
json_object_object_add(json, "wrap_scroll", json_object_object_add(json, "wrap_scroll",
json_object_new_boolean(bar->wrap_scroll)); json_object_new_boolean(bar->wrap_scroll));
json_object_object_add(json, "window_title",
json_object_new_boolean(bar->window_title));
json_object_object_add(json, "workspace_buttons", json_object_object_add(json, "workspace_buttons",
json_object_new_boolean(bar->workspace_buttons)); json_object_new_boolean(bar->workspace_buttons));
json_object_object_add(json, "strip_workspace_numbers", json_object_object_add(json, "strip_workspace_numbers",

View file

@ -137,6 +137,7 @@ sway_sources = files(
'commands/bar/tray_bind.c', 'commands/bar/tray_bind.c',
'commands/bar/tray_output.c', 'commands/bar/tray_output.c',
'commands/bar/tray_padding.c', 'commands/bar/tray_padding.c',
'commands/bar/window_title.c',
'commands/bar/workspace_buttons.c', 'commands/bar/workspace_buttons.c',
'commands/bar/wrap_scroll.c', 'commands/bar/wrap_scroll.c',

View file

@ -48,6 +48,9 @@ Sway allows configuring swaybar in the sway configuration file.
Enables or disables wrapping when scrolling through workspaces with the Enables or disables wrapping when scrolling through workspaces with the
scroll wheel. Default is _no_. scroll wheel. Default is _no_.
*window_title* yes|no
Enables or disables focused window title on the bar. Default is _no_.
*workspace_buttons* yes|no *workspace_buttons* yes|no
Enables or disables workspace buttons on the bar. Default is _yes_. Enables or disables workspace buttons on the bar. Default is _yes_.

View file

@ -173,6 +173,7 @@ static bool ipc_parse_config(
json_object_put(bar_config); json_object_put(bar_config);
return false; return false;
} }
json_object *window_title;
json_object *markup, *mode, *hidden_state, *position, *status_command; json_object *markup, *mode, *hidden_state, *position, *status_command;
json_object *font, *gaps, *bar_height, *wrap_scroll, *workspace_buttons; json_object *font, *gaps, *bar_height, *wrap_scroll, *workspace_buttons;
json_object *strip_workspace_numbers, *strip_workspace_name; json_object *strip_workspace_numbers, *strip_workspace_name;
@ -186,6 +187,7 @@ static bool ipc_parse_config(
json_object_object_get_ex(bar_config, "gaps", &gaps); json_object_object_get_ex(bar_config, "gaps", &gaps);
json_object_object_get_ex(bar_config, "bar_height", &bar_height); json_object_object_get_ex(bar_config, "bar_height", &bar_height);
json_object_object_get_ex(bar_config, "wrap_scroll", &wrap_scroll); json_object_object_get_ex(bar_config, "wrap_scroll", &wrap_scroll);
json_object_object_get_ex(bar_config, "window_title", &window_title);
json_object_object_get_ex(bar_config, "workspace_buttons", &workspace_buttons); json_object_object_get_ex(bar_config, "workspace_buttons", &workspace_buttons);
json_object_object_get_ex(bar_config, "strip_workspace_numbers", &strip_workspace_numbers); json_object_object_get_ex(bar_config, "strip_workspace_numbers", &strip_workspace_numbers);
json_object_object_get_ex(bar_config, "strip_workspace_name", &strip_workspace_name); json_object_object_get_ex(bar_config, "strip_workspace_name", &strip_workspace_name);
@ -226,6 +228,9 @@ static bool ipc_parse_config(
if (wrap_scroll) { if (wrap_scroll) {
config->wrap_scroll = json_object_get_boolean(wrap_scroll); config->wrap_scroll = json_object_get_boolean(wrap_scroll);
} }
if (window_title) {
config->window_title = json_object_get_boolean(window_title);
}
if (workspace_buttons) { if (workspace_buttons) {
config->workspace_buttons = json_object_get_boolean(workspace_buttons); config->workspace_buttons = json_object_get_boolean(workspace_buttons);
} }
@ -480,7 +485,8 @@ bool ipc_initialize(struct swaybar *bar) {
struct swaybar_config *config = bar->config; struct swaybar_config *config = bar->config;
char subscribe[128]; // suitably large buffer char subscribe[128]; // suitably large buffer
len = snprintf(subscribe, 128, len = snprintf(subscribe, 128,
"[ \"barconfig_update\" , \"bar_state_update\" %s %s ]", "[ \"barconfig_update\" , \"bar_state_update\" %s %s %s ]",
config->window_title ? ", \"window\"" : "",
config->binding_mode_indicator ? ", \"mode\"" : "", config->binding_mode_indicator ? ", \"mode\"" : "",
config->workspace_buttons ? ", \"workspace\"" : ""); config->workspace_buttons ? ", \"workspace\"" : "");
free(ipc_single_command(bar->ipc_event_socketfd, free(ipc_single_command(bar->ipc_event_socketfd,
@ -509,6 +515,49 @@ static bool handle_bar_state_update(struct swaybar *bar, json_object *event) {
return determine_bar_visibility(bar, false); return determine_bar_visibility(bar, false);
} }
static bool handle_title_update(struct swaybar *bar,
json_object *json_window_event) {
json_object *json_container;
json_object_object_get_ex(json_window_event, "container",
&json_container);
struct swaybar_config *config = bar->config;
json_object *json_change;
json_object_object_get_ex(json_window_event, "change", &json_change);
const char *change = json_object_get_string(json_change);
if (strcmp(change, "close") == 0) {
json_object *json_id;
json_object_object_get_ex(json_container, "id", &json_id);
uint64_t app_id = json_object_get_int64(json_id);
if (config->window_app_id == app_id) {
// The focused window was closed so remove the title
config->window_app_id = 0;
if (config->title) {
free(config->title);
}
config->title = NULL;
}
return true;
}
json_object *json_focused;
json_object_object_get_ex(json_container, "focused", &json_focused);
if (json_object_get_boolean(json_focused)) {
json_object *json_name;
json_object_object_get_ex(json_container, "name", &json_name);
if (config->title) {
free(config->title);
}
config->title = strdup(json_object_get_string(json_name));
json_object *json_id;
json_object_object_get_ex(json_container, "id", &json_id);
config->window_app_id = json_object_get_int64(json_id);
return true;
}
return false;
}
static bool handle_barconfig_update(struct swaybar *bar, static bool handle_barconfig_update(struct swaybar *bar,
json_object *json_config) { json_object *json_config) {
json_object *json_id; json_object *json_id;
@ -576,6 +625,9 @@ bool handle_ipc_readable(struct swaybar *bar) {
bool bar_is_dirty = true; bool bar_is_dirty = true;
switch (resp->type) { switch (resp->type) {
case IPC_EVENT_WINDOW:
bar_is_dirty = handle_title_update(bar, result);
break;
case IPC_EVENT_WORKSPACE: case IPC_EVENT_WORKSPACE:
bar_is_dirty = ipc_get_workspaces(bar); bar_is_dirty = ipc_get_workspaces(bar);
break; break;

View file

@ -536,6 +536,45 @@ static uint32_t render_binding_mode_indicator(cairo_t *cairo,
return output->height; return output->height;
} }
static uint32_t render_window_title(cairo_t *cairo,
struct swaybar_output *output, double x) {
const char *title = output->bar->config->title;
if (!title) {
return 0;
}
struct swaybar_config *config = output->bar->config;
int text_width, text_height;
get_text_size(cairo, config->font, &text_width, &text_height, NULL,
output->scale, output->bar->mode_pango_markup,
"%s", title);
int ws_vertical_padding = WS_VERTICAL_PADDING * output->scale;
int ws_horizontal_padding = WS_HORIZONTAL_PADDING * output->scale;
int border_width = BORDER_WIDTH * output->scale;
uint32_t ideal_height = text_height + ws_vertical_padding * 2
+ border_width * 2;
uint32_t ideal_surface_height = ideal_height / output->scale;
if (!output->bar->config->height &&
output->height < ideal_surface_height) {
return ideal_surface_height;
}
uint32_t width = text_width + ws_horizontal_padding * 2 + border_width * 2;
uint32_t height = output->height * output->scale;
cairo_set_source_u32(cairo, config->colors.background);
cairo_rectangle(cairo, x, 0, width, height);
cairo_fill(cairo);
double text_y = height / 2.0 - text_height / 2.0;
cairo_set_source_u32(cairo, config->colors.statusline);
cairo_move_to(cairo, x + width / 2 - text_width / 2, (int)floor(text_y));
pango_printf(cairo, config->font, output->scale,
output->bar->mode_pango_markup, "%s", title);
return output->height;
}
static enum hotspot_event_handling workspace_hotspot_callback( static enum hotspot_event_handling workspace_hotspot_callback(
struct swaybar_output *output, struct swaybar_hotspot *hotspot, struct swaybar_output *output, struct swaybar_hotspot *hotspot,
int x, int y, uint32_t button, void *data) { int x, int y, uint32_t button, void *data) {
@ -660,6 +699,11 @@ 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->window_title) {
uint32_t h = render_window_title(cairo, output, x);
max_height = h > max_height ? h : max_height;
}
return max_height > output->height ? max_height : output->height; return max_height > output->height ? max_height : output->height;
} }