mirror of
https://github.com/swaywm/sway.git
synced 2026-04-24 06:46:22 -04:00
Display window title and icon in swaybar
Signed-off-by: Felix Weilbach <felix.weilbach@t-online.de>
This commit is contained in:
parent
c12169953a
commit
8fa71290af
13 changed files with 454 additions and 15 deletions
|
|
@ -136,3 +136,37 @@ void pango_printf(cairo_t *cairo, const char *font,
|
|||
g_object_unref(layout);
|
||||
free(buf);
|
||||
}
|
||||
|
||||
void pango_printf_ellipsize(cairo_t *cairo,
|
||||
const char *font,
|
||||
double scale,
|
||||
bool markup,
|
||||
double width,
|
||||
const char *fmt,
|
||||
...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
// Add one since vsnprintf excludes null terminator.
|
||||
int length = vsnprintf(NULL, 0, fmt, args) + 1;
|
||||
va_end(args);
|
||||
|
||||
char *buf = malloc(length);
|
||||
if (buf == NULL) {
|
||||
sway_log(SWAY_ERROR, "Failed to allocate memory");
|
||||
return;
|
||||
}
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buf, length, fmt, args);
|
||||
va_end(args);
|
||||
PangoLayout *layout = get_pango_layout(cairo, font, buf, scale, markup);
|
||||
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END);
|
||||
pango_layout_set_width(layout, width * PANGO_SCALE);
|
||||
cairo_font_options_t *fo = cairo_font_options_create();
|
||||
cairo_get_font_options(cairo, fo);
|
||||
pango_cairo_context_set_font_options(pango_layout_get_context(layout), fo);
|
||||
cairo_font_options_destroy(fo);
|
||||
pango_cairo_update_layout(cairo, layout);
|
||||
pango_cairo_show_layout(cairo, layout);
|
||||
g_object_unref(layout);
|
||||
free(buf);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,5 +19,12 @@ void get_text_size(cairo_t *cairo, const char *font, int *width, int *height,
|
|||
int *baseline, double scale, bool markup, const char *fmt, ...);
|
||||
void pango_printf(cairo_t *cairo, const char *font,
|
||||
double scale, bool markup, const char *fmt, ...);
|
||||
void pango_printf_ellipsize(cairo_t *cairo,
|
||||
const char *font,
|
||||
double scale,
|
||||
bool markup,
|
||||
double width,
|
||||
const char *fmt,
|
||||
...);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ struct swaybar_output;
|
|||
struct swaybar_tray;
|
||||
#endif
|
||||
struct swaybar_workspace;
|
||||
struct swaybar_window;
|
||||
struct loop;
|
||||
|
||||
struct swaybar {
|
||||
|
|
@ -44,6 +45,11 @@ struct swaybar {
|
|||
struct wl_list unused_outputs; // swaybar_output::link
|
||||
struct wl_list seats; // swaybar_seat::link
|
||||
|
||||
struct swaybar_window *focused_window;
|
||||
|
||||
// TOOD: Better name
|
||||
bool workspace_changed;
|
||||
|
||||
#if HAVE_TRAY
|
||||
struct swaybar_tray *tray;
|
||||
#endif
|
||||
|
|
@ -89,6 +95,12 @@ struct swaybar_workspace {
|
|||
bool urgent;
|
||||
};
|
||||
|
||||
struct swaybar_window {
|
||||
char *name;
|
||||
char *icon_name;
|
||||
cairo_surface_t *icon;
|
||||
};
|
||||
|
||||
bool bar_setup(struct swaybar *bar, const char *socket_path);
|
||||
void bar_run(struct swaybar *bar);
|
||||
void bar_teardown(struct swaybar *bar);
|
||||
|
|
@ -109,6 +121,7 @@ void set_bar_dirty(struct swaybar *bar);
|
|||
*/
|
||||
bool determine_bar_visibility(struct swaybar *bar, bool moving_layer);
|
||||
void free_workspaces(struct wl_list *list);
|
||||
void free_window(struct swaybar_window *window);
|
||||
|
||||
void status_in(int fd, short mask, void *data);
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
bool ipc_initialize(struct swaybar *bar);
|
||||
bool handle_ipc_readable(struct swaybar *bar);
|
||||
bool ipc_get_workspaces(struct swaybar *bar);
|
||||
bool ipc_set_focused_window(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);
|
||||
|
||||
|
|
|
|||
|
|
@ -27,10 +27,12 @@ struct icon_theme {
|
|||
char *dir;
|
||||
list_t *subdirs; // struct icon_theme_subdir *
|
||||
};
|
||||
|
||||
list_t *get_basedirs(void);
|
||||
void init_themes(list_t **themes, list_t **basedirs);
|
||||
void finish_themes(list_t *themes, list_t *basedirs);
|
||||
|
||||
char *append_path_safe(const char *base_path, const char *append_path);
|
||||
|
||||
/*
|
||||
* Finds an icon of a specified size given a list of themes and base directories.
|
||||
* If the icon is found, the pointers min_size & max_size are set to minimum &
|
||||
|
|
|
|||
|
|
@ -358,7 +358,8 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data)
|
|||
if (e->fullscreen && e->output && e->output->data) {
|
||||
struct sway_output *output = e->output->data;
|
||||
struct sway_workspace *ws = output_get_active_workspace(output);
|
||||
if (ws && !container_is_scratchpad_hidden(container)) {
|
||||
if (ws && !container_is_scratchpad_hidden(container) &&
|
||||
container->pending.workspace != ws) {
|
||||
if (container_is_floating(container)) {
|
||||
workspace_add_floating(ws, container);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -40,6 +40,17 @@ void free_workspaces(struct wl_list *list) {
|
|||
}
|
||||
}
|
||||
|
||||
void free_window(struct swaybar_window *window) {
|
||||
if (window->icon_name) {
|
||||
free(window->icon_name);
|
||||
}
|
||||
if (window->icon) {
|
||||
cairo_surface_destroy(window->icon);
|
||||
}
|
||||
free(window->name);
|
||||
free(window);
|
||||
}
|
||||
|
||||
static void swaybar_output_free(struct swaybar_output *output) {
|
||||
if (!output) {
|
||||
return;
|
||||
|
|
@ -455,6 +466,7 @@ bool bar_setup(struct swaybar *bar, const char *socket_path) {
|
|||
if (bar->config->workspace_buttons) {
|
||||
ipc_get_workspaces(bar);
|
||||
}
|
||||
ipc_set_focused_window(bar);
|
||||
determine_bar_visibility(bar, false);
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
96
swaybar/desktop.c
Normal file
96
swaybar/desktop.c
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
#define _POSIX_C_SOURCE 200809
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "swaybar/tray/icon.h"
|
||||
#include "desktop.h"
|
||||
#include "log.h"
|
||||
|
||||
static list_t *get_desktop_files_basedirs() {
|
||||
list_t *basedirs = create_list();
|
||||
// TODO: Get correct list of directories
|
||||
list_add(basedirs, "/usr/share/applications");
|
||||
return basedirs;
|
||||
}
|
||||
|
||||
static char *load_desktop_entry(const char *app_name, list_t *basedirs) {
|
||||
assert(app_name);
|
||||
assert(basedirs);
|
||||
|
||||
size_t desktop_filename_len = snprintf(NULL, 0, "%s.desktop", app_name) + 1;
|
||||
char *desktop_filename = malloc(desktop_filename_len);
|
||||
snprintf(desktop_filename, desktop_filename_len, "%s.desktop", app_name);
|
||||
|
||||
for (int i = 0; i < basedirs->length; ++i) {
|
||||
const char *basedir = basedirs->items[i];
|
||||
|
||||
DIR *d;
|
||||
struct dirent *dir;
|
||||
d = opendir(basedir);
|
||||
if (d) {
|
||||
while ((dir = readdir(d)) != NULL) {
|
||||
if (strcmp(desktop_filename, dir->d_name) == 0) {
|
||||
char *buf = append_path_safe(basedir, desktop_filename);
|
||||
|
||||
FILE *f = fopen(buf, "rb");
|
||||
assert(f);
|
||||
fseek(f, 0, SEEK_END);
|
||||
long fsize = ftell(f);
|
||||
fseek(f, 0, SEEK_SET); /* same as rewind(f); */
|
||||
|
||||
char *string = malloc(fsize + 1);
|
||||
fread(string, 1, fsize, f);
|
||||
fclose(f);
|
||||
|
||||
string[fsize] = 0;
|
||||
closedir(d);
|
||||
|
||||
return string;
|
||||
}
|
||||
}
|
||||
closedir(d);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *load_desktop_entry_from_xdgdirs(const char *app_name) {
|
||||
list_t *basedirs = get_desktop_files_basedirs();
|
||||
return load_desktop_entry(app_name, basedirs);
|
||||
}
|
||||
|
||||
char *get_icon_name_from_desktop_entry(const char *desktop_entry) {
|
||||
if (!desktop_entry) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *desktop_entry_start = strdup(desktop_entry);
|
||||
char *cur_line = desktop_entry_start;
|
||||
char *icon_name = NULL;
|
||||
while (cur_line) {
|
||||
char *next_line = strchr(cur_line, '\n');
|
||||
if (next_line) {
|
||||
*next_line = 0;
|
||||
}
|
||||
|
||||
if (strncmp(cur_line, "Icon=", 5) == 0) {
|
||||
const char *icon_name_start = strchr(cur_line, '=') + 1;
|
||||
icon_name = strdup(icon_name_start);
|
||||
break;
|
||||
}
|
||||
|
||||
if (next_line) {
|
||||
*next_line = '\n';
|
||||
}
|
||||
cur_line = next_line ? (next_line + 1) : NULL;
|
||||
}
|
||||
free(desktop_entry_start);
|
||||
|
||||
return icon_name;
|
||||
}
|
||||
8
swaybar/desktop.h
Normal file
8
swaybar/desktop.h
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef _SWAYBAR_DESKTOP_H
|
||||
#define _SWAYBAR_DESKTOP_H
|
||||
|
||||
char *load_desktop_entry_from_xdgdirs(const char *app_name);
|
||||
|
||||
char *get_icon_name_from_desktop_entry(const char *desktop_entry);
|
||||
|
||||
#endif
|
||||
118
swaybar/ipc.c
118
swaybar/ipc.c
|
|
@ -5,14 +5,18 @@
|
|||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <json.h>
|
||||
#include <assert.h>
|
||||
#include "swaybar/config.h"
|
||||
#include "swaybar/ipc.h"
|
||||
#include "swaybar/status_line.h"
|
||||
#if HAVE_TRAY
|
||||
#include "swaybar/tray/tray.h"
|
||||
#endif
|
||||
#include "desktop.h"
|
||||
#include "config.h"
|
||||
#include "swaybar/tray/icon.h"
|
||||
#include "ipc-client.h"
|
||||
#include "background-image.h"
|
||||
#include "list.h"
|
||||
#include "log.h"
|
||||
#include "loop.h"
|
||||
|
|
@ -427,7 +431,7 @@ bool ipc_initialize(struct swaybar *bar) {
|
|||
struct swaybar_config *config = bar->config;
|
||||
char subscribe[128]; // suitably large buffer
|
||||
len = snprintf(subscribe, 128,
|
||||
"[ \"barconfig_update\" , \"bar_state_update\" %s %s ]",
|
||||
"[ \"barconfig_update\" , \"bar_state_update\", \"window\" %s %s ]",
|
||||
config->binding_mode_indicator ? ", \"mode\"" : "",
|
||||
config->workspace_buttons ? ", \"workspace\"" : "");
|
||||
free(ipc_single_command(bar->ipc_event_socketfd,
|
||||
|
|
@ -541,6 +545,112 @@ static bool handle_barconfig_update(struct swaybar *bar, const char *payload,
|
|||
return true;
|
||||
}
|
||||
|
||||
static const char *get_app_name_from_node(json_object *json_node) {
|
||||
assert(json_node);
|
||||
|
||||
json_object *json_app_id;
|
||||
json_object_object_get_ex(json_node, "app_id", &json_app_id);
|
||||
if (!json_app_id) {
|
||||
// If no app_id is found, take the instance property from window_properties
|
||||
json_object *json_window_properties;
|
||||
json_object_object_get_ex(
|
||||
json_node, "window_properties", &json_window_properties);
|
||||
assert(json_window_properties);
|
||||
|
||||
json_object *json_instance;
|
||||
json_object_object_get_ex(
|
||||
json_window_properties, "instance", &json_instance);
|
||||
assert(json_instance);
|
||||
|
||||
json_app_id = json_instance;
|
||||
}
|
||||
|
||||
const char *app_id = json_object_get_string(json_app_id);
|
||||
assert(app_id);
|
||||
|
||||
return app_id;
|
||||
}
|
||||
|
||||
static struct swaybar_window *get_focused_window_from_nodes(
|
||||
json_object *json_nodes) {
|
||||
assert(json_nodes);
|
||||
|
||||
size_t json_nodes_length = json_object_array_length(json_nodes);
|
||||
for (size_t i = 0; i < json_nodes_length; ++i) {
|
||||
json_object *json_node;
|
||||
json_node = json_object_array_get_idx(json_nodes, i);
|
||||
struct json_object *json_focused;
|
||||
json_object_object_get_ex(json_node, "focused", &json_focused);
|
||||
assert(json_focused);
|
||||
bool focused = json_object_get_boolean(json_focused);
|
||||
struct json_object *json_type;
|
||||
json_object_object_get_ex(json_node, "type", &json_type);
|
||||
assert(json_type);
|
||||
const char* type = json_object_get_string(json_type);
|
||||
assert(type);
|
||||
|
||||
if (focused && ((strcmp(type, "con") == 0) ||
|
||||
(strcmp(type, "floating_con") == 0))) {
|
||||
json_object *json_name;
|
||||
json_object_object_get_ex(json_node, "name", &json_name);
|
||||
assert(json_name);
|
||||
const char *name = json_object_get_string(json_name);
|
||||
assert(name);
|
||||
|
||||
const char *app_name = get_app_name_from_node(json_node);
|
||||
char *desktop_entry = load_desktop_entry_from_xdgdirs(app_name);
|
||||
char *icon_name = get_icon_name_from_desktop_entry(desktop_entry);
|
||||
free(desktop_entry);
|
||||
|
||||
struct swaybar_window *window =
|
||||
calloc(1, sizeof(struct swaybar_window));
|
||||
window->name = strdup(name);
|
||||
window->icon_name = icon_name;
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
struct json_object *json_inner_nodes;
|
||||
json_object_object_get_ex(json_node, "nodes", &json_inner_nodes);
|
||||
if (json_nodes) {
|
||||
struct swaybar_window *window =
|
||||
get_focused_window_from_nodes(json_inner_nodes);
|
||||
if (window) {
|
||||
return window;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool ipc_set_focused_window(struct swaybar *bar) {
|
||||
uint32_t len = 0;
|
||||
char *res = ipc_single_command(bar->ipc_socketfd,
|
||||
IPC_GET_TREE, NULL, &len);
|
||||
json_object *results = json_tokener_parse(res);
|
||||
if (!results) {
|
||||
free(res);
|
||||
return false;
|
||||
}
|
||||
|
||||
json_object *json_nodes;
|
||||
json_object_object_get_ex(results, "nodes", &json_nodes);
|
||||
assert(json_nodes);
|
||||
struct swaybar_window *window = get_focused_window_from_nodes(json_nodes);
|
||||
if (bar->focused_window) {
|
||||
free_window(bar->focused_window);
|
||||
bar->focused_window = NULL;
|
||||
}
|
||||
if (window) {
|
||||
bar->focused_window = window;
|
||||
}
|
||||
|
||||
bar->workspace_changed = false;
|
||||
// TODO: cache
|
||||
return true;
|
||||
}
|
||||
|
||||
bool handle_ipc_readable(struct swaybar *bar) {
|
||||
struct ipc_response *resp = ipc_recv_response(bar->ipc_event_socketfd);
|
||||
if (!resp) {
|
||||
|
|
@ -571,7 +681,10 @@ bool handle_ipc_readable(struct swaybar *bar) {
|
|||
bool bar_is_dirty = true;
|
||||
switch (resp->type) {
|
||||
case IPC_EVENT_WORKSPACE:
|
||||
bar->workspace_changed = true;
|
||||
bar_is_dirty = ipc_get_workspaces(bar);
|
||||
const bool focused_window_change = ipc_set_focused_window(bar);
|
||||
bar_is_dirty = bar_is_dirty ? true : focused_window_change;
|
||||
break;
|
||||
case IPC_EVENT_MODE: {
|
||||
json_object *json_change, *json_pango_markup;
|
||||
|
|
@ -598,6 +711,9 @@ bool handle_ipc_readable(struct swaybar *bar) {
|
|||
case IPC_EVENT_BAR_STATE_UPDATE:
|
||||
bar_is_dirty = handle_bar_state_update(bar, result);
|
||||
break;
|
||||
case IPC_EVENT_WINDOW:
|
||||
bar_is_dirty = ipc_set_focused_window(bar);
|
||||
break;
|
||||
default:
|
||||
bar_is_dirty = false;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ executable(
|
|||
'main.c',
|
||||
'render.c',
|
||||
'status_line.c',
|
||||
'desktop.c',
|
||||
tray_files
|
||||
],
|
||||
include_directories: [sway_inc],
|
||||
|
|
|
|||
147
swaybar/render.c
147
swaybar/render.c
|
|
@ -14,6 +14,9 @@
|
|||
#include "swaybar/ipc.h"
|
||||
#include "swaybar/render.h"
|
||||
#include "swaybar/status_line.h"
|
||||
#include "swaybar/tray/icon.h"
|
||||
#include "log.h"
|
||||
#include "background-image.h"
|
||||
#if HAVE_TRAY
|
||||
#include "swaybar/tray/tray.h"
|
||||
#endif
|
||||
|
|
@ -121,6 +124,51 @@ static uint32_t render_status_line_text(struct render_context *ctx, double *x) {
|
|||
return output->height;
|
||||
}
|
||||
|
||||
static uint32_t render_focused_window_title(struct render_context *ctx, double *x, double max_width) {
|
||||
struct swaybar_output *output = ctx->output;
|
||||
const char *text = output->bar->focused_window ? output->bar->focused_window->name : "";
|
||||
if (!text) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
cairo_t *cairo = ctx->cairo;
|
||||
struct swaybar_config *config = output->bar->config;
|
||||
uint32_t fontcolor = output->focused ?
|
||||
config->colors.focused_statusline : config->colors.statusline;
|
||||
cairo_set_source_u32(cairo, fontcolor);
|
||||
|
||||
int text_width, text_height;
|
||||
get_text_size(cairo,
|
||||
config->font,
|
||||
&text_width,
|
||||
&text_height,
|
||||
NULL,
|
||||
output->scale,
|
||||
config->pango_markup,
|
||||
"%s",
|
||||
text);
|
||||
|
||||
double ws_vertical_padding = config->status_padding * output->scale;
|
||||
int margin = 6 * output->scale;
|
||||
|
||||
uint32_t ideal_height = text_height + ws_vertical_padding * 2;
|
||||
uint32_t ideal_surface_height = ideal_height / output->scale;
|
||||
if (!output->bar->config->height &&
|
||||
output->height < ideal_surface_height) {
|
||||
return ideal_surface_height;
|
||||
}
|
||||
|
||||
/* *x += margin; */
|
||||
uint32_t height = output->height * output->scale;
|
||||
double text_y = height / 2.0 - text_height / 2.0;
|
||||
cairo_move_to(cairo, *x, (int)floor(text_y));
|
||||
choose_text_aa_mode(ctx, fontcolor);
|
||||
pango_printf_ellipsize(cairo, config->font, output->scale,
|
||||
config->pango_markup, max_width, "%s", text);
|
||||
*x += margin;
|
||||
return output->height;
|
||||
}
|
||||
|
||||
static void render_sharp_rectangle(cairo_t *cairo, uint32_t color,
|
||||
double x, double y, double width, double height) {
|
||||
cairo_save(cairo);
|
||||
|
|
@ -539,7 +587,7 @@ static uint32_t render_status_line(struct render_context *ctx, double *x) {
|
|||
}
|
||||
|
||||
static uint32_t render_binding_mode_indicator(struct render_context *ctx,
|
||||
double x) {
|
||||
double *x) {
|
||||
struct swaybar_output *output = ctx->output;
|
||||
const char *mode = output->bar->mode;
|
||||
if (!mode) {
|
||||
|
|
@ -573,25 +621,28 @@ static uint32_t render_binding_mode_indicator(struct render_context *ctx,
|
|||
cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
|
||||
cairo_set_source_u32(cairo, config->colors.binding_mode.background);
|
||||
ctx->background_color = config->colors.binding_mode.background;
|
||||
cairo_rectangle(cairo, x, 0, width, height);
|
||||
cairo_rectangle(cairo, *x, 0, width, height);
|
||||
cairo_fill(cairo);
|
||||
|
||||
cairo_set_source_u32(cairo, config->colors.binding_mode.border);
|
||||
cairo_rectangle(cairo, x, 0, width, border_width);
|
||||
cairo_rectangle(cairo, *x, 0, width, border_width);
|
||||
cairo_fill(cairo);
|
||||
cairo_rectangle(cairo, x, 0, border_width, height);
|
||||
cairo_rectangle(cairo, *x, 0, border_width, height);
|
||||
cairo_fill(cairo);
|
||||
cairo_rectangle(cairo, x + width - border_width, 0, border_width, height);
|
||||
cairo_rectangle(cairo, *x + width - border_width, 0, border_width, height);
|
||||
cairo_fill(cairo);
|
||||
cairo_rectangle(cairo, x, height - border_width, width, border_width);
|
||||
cairo_rectangle(cairo, *x, height - border_width, width, border_width);
|
||||
cairo_fill(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));
|
||||
cairo_move_to(cairo, *x + width / 2 - text_width / 2, (int)floor(text_y));
|
||||
choose_text_aa_mode(ctx, config->colors.binding_mode.text);
|
||||
pango_printf(cairo, config->font, output->scale,
|
||||
output->bar->mode_pango_markup, "%s", mode);
|
||||
|
||||
*x += width;
|
||||
|
||||
return output->height;
|
||||
}
|
||||
|
||||
|
|
@ -681,6 +732,76 @@ static uint32_t render_workspace_button(struct render_context *ctx,
|
|||
return output->height;
|
||||
}
|
||||
|
||||
uint32_t render_focused_window_icon(cairo_t *cairo,
|
||||
struct swaybar_output *output,
|
||||
double *x) {
|
||||
assert(output);
|
||||
assert(output->bar);
|
||||
|
||||
if (!output->bar->focused_window) {
|
||||
return output->height;
|
||||
}
|
||||
|
||||
uint32_t height = output->height * output->scale;
|
||||
int padding = 4;
|
||||
int target_size = height - 2 * padding;
|
||||
|
||||
char *icon_name = output->bar->focused_window->icon_name;
|
||||
cairo_surface_t *icon = NULL;
|
||||
if (icon_name) {
|
||||
char *icon_theme = output->bar->config->icon_theme;
|
||||
list_t *basedirs = get_basedirs();
|
||||
int min_size = 0;
|
||||
int max_size = 0;
|
||||
|
||||
list_t *themes = create_list();
|
||||
// TODO: Load correct theme
|
||||
list_add(themes, "Adwaita");
|
||||
|
||||
assert(output->bar->tray);
|
||||
assert(output->bar->tray->themes);
|
||||
char *icon_path = find_icon(output->bar->tray->themes,
|
||||
basedirs,
|
||||
icon_name,
|
||||
target_size,
|
||||
icon_theme,
|
||||
&min_size,
|
||||
&max_size);
|
||||
icon = load_background_image(icon_path);
|
||||
} else {
|
||||
// TODO: Generate a image on the fly
|
||||
icon = load_background_image(
|
||||
"/usr/share/icons/Adwaita/16x16/apps/"
|
||||
"utilities-terminal-symbolic.symbolic.png");
|
||||
}
|
||||
assert(icon);
|
||||
if (!icon) {
|
||||
return output->height;
|
||||
}
|
||||
|
||||
int icon_size;
|
||||
int actual_size = cairo_image_surface_get_height(icon);
|
||||
icon_size = actual_size < target_size ?
|
||||
actual_size*(target_size/actual_size) : target_size;
|
||||
icon = cairo_image_surface_scale(icon, icon_size, icon_size);
|
||||
|
||||
int padded_size = icon_size + 2 * padding;
|
||||
int y = floor((height - padded_size) / 2.0);
|
||||
|
||||
cairo_operator_t op = cairo_get_operator(cairo);
|
||||
cairo_set_operator(cairo, CAIRO_OPERATOR_OVER);
|
||||
cairo_set_source_surface(cairo, icon, *x + padding, y + padding);
|
||||
cairo_rectangle(cairo, *x, y, padded_size, padded_size);
|
||||
cairo_fill(cairo);
|
||||
cairo_set_operator(cairo, op);
|
||||
|
||||
*x += padded_size;
|
||||
|
||||
cairo_surface_destroy(icon);
|
||||
|
||||
return output->height;
|
||||
}
|
||||
|
||||
static uint32_t render_to_cairo(struct render_context *ctx) {
|
||||
cairo_t *cairo = ctx->cairo;
|
||||
struct swaybar_output *output = ctx->output;
|
||||
|
|
@ -717,6 +838,8 @@ static uint32_t render_to_cairo(struct render_context *ctx) {
|
|||
uint32_t h = render_status_line(ctx, &x);
|
||||
max_height = h > max_height ? h : max_height;
|
||||
}
|
||||
|
||||
double old_x = x;
|
||||
x = 0;
|
||||
if (config->workspace_buttons) {
|
||||
struct swaybar_workspace *ws;
|
||||
|
|
@ -726,7 +849,15 @@ static uint32_t render_to_cairo(struct render_context *ctx) {
|
|||
}
|
||||
}
|
||||
if (config->binding_mode_indicator) {
|
||||
uint32_t h = render_binding_mode_indicator(ctx, x);
|
||||
uint32_t h = render_binding_mode_indicator(ctx, &x);
|
||||
max_height = h > max_height ? h : max_height;
|
||||
}
|
||||
|
||||
if (!bar->workspace_changed && output->focused) {
|
||||
uint32_t h = render_focused_window_icon(cairo, output, &x);
|
||||
max_height = h > max_height ? h : max_height;
|
||||
old_x -= x;
|
||||
h = render_focused_window_title(ctx, &x, old_x);
|
||||
max_height = h > max_height ? h : max_height;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#define _POSIX_C_SOURCE 200809L
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
#include <dirent.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
|
@ -23,7 +24,25 @@ static bool dir_exists(char *path) {
|
|||
return stat(path, &sb) == 0 && S_ISDIR(sb.st_mode);
|
||||
}
|
||||
|
||||
static list_t *get_basedirs(void) {
|
||||
char* append_path_safe(const char * base_path, const char * append_path) {
|
||||
assert(base_path);
|
||||
assert(append_path);
|
||||
|
||||
size_t base_path_len = strlen(base_path);
|
||||
if (base_path[base_path_len - 1] == '/') {
|
||||
size_t path_len = snprintf(NULL, 0, "%s%s", base_path, append_path) + 1;
|
||||
char *path = malloc(path_len);
|
||||
snprintf(path, path_len, "%s%s", base_path, append_path);
|
||||
return path;
|
||||
}
|
||||
|
||||
size_t path_len = snprintf(NULL, 0, "%s/%s", base_path, append_path) + 1;
|
||||
char *path = malloc(path_len);
|
||||
snprintf(path, path_len, "%s/%s", base_path, append_path);
|
||||
return path;
|
||||
}
|
||||
|
||||
list_t *get_basedirs(void) {
|
||||
list_t *basedirs = create_list();
|
||||
list_add(basedirs, strdup("$HOME/.icons")); // deprecated
|
||||
|
||||
|
|
@ -40,9 +59,7 @@ static list_t *get_basedirs(void) {
|
|||
data_dirs = strdup(data_dirs);
|
||||
char *dir = strtok(data_dirs, ":");
|
||||
do {
|
||||
size_t path_len = snprintf(NULL, 0, "%s/icons", dir) + 1;
|
||||
char *path = malloc(path_len);
|
||||
snprintf(path, path_len, "%s/icons", dir);
|
||||
char *path = append_path_safe(dir, "icons");
|
||||
list_add(basedirs, path);
|
||||
} while ((dir = strtok(NULL, ":")));
|
||||
free(data_dirs);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue