mirror of
https://github.com/swaywm/sway.git
synced 2026-04-25 06:46:24 -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);
|
g_object_unref(layout);
|
||||||
free(buf);
|
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, ...);
|
int *baseline, double scale, bool markup, const char *fmt, ...);
|
||||||
void pango_printf(cairo_t *cairo, const char *font,
|
void pango_printf(cairo_t *cairo, const char *font,
|
||||||
double scale, bool markup, const char *fmt, ...);
|
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
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ struct swaybar_output;
|
||||||
struct swaybar_tray;
|
struct swaybar_tray;
|
||||||
#endif
|
#endif
|
||||||
struct swaybar_workspace;
|
struct swaybar_workspace;
|
||||||
|
struct swaybar_window;
|
||||||
struct loop;
|
struct loop;
|
||||||
|
|
||||||
struct swaybar {
|
struct swaybar {
|
||||||
|
|
@ -44,6 +45,11 @@ struct swaybar {
|
||||||
struct wl_list unused_outputs; // swaybar_output::link
|
struct wl_list unused_outputs; // swaybar_output::link
|
||||||
struct wl_list seats; // swaybar_seat::link
|
struct wl_list seats; // swaybar_seat::link
|
||||||
|
|
||||||
|
struct swaybar_window *focused_window;
|
||||||
|
|
||||||
|
// TOOD: Better name
|
||||||
|
bool workspace_changed;
|
||||||
|
|
||||||
#if HAVE_TRAY
|
#if HAVE_TRAY
|
||||||
struct swaybar_tray *tray;
|
struct swaybar_tray *tray;
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -89,6 +95,12 @@ struct swaybar_workspace {
|
||||||
bool urgent;
|
bool urgent;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct swaybar_window {
|
||||||
|
char *name;
|
||||||
|
char *icon_name;
|
||||||
|
cairo_surface_t *icon;
|
||||||
|
};
|
||||||
|
|
||||||
bool bar_setup(struct swaybar *bar, const char *socket_path);
|
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);
|
||||||
|
|
@ -109,6 +121,7 @@ void set_bar_dirty(struct swaybar *bar);
|
||||||
*/
|
*/
|
||||||
bool determine_bar_visibility(struct swaybar *bar, bool moving_layer);
|
bool determine_bar_visibility(struct swaybar *bar, bool moving_layer);
|
||||||
void free_workspaces(struct wl_list *list);
|
void free_workspaces(struct wl_list *list);
|
||||||
|
void free_window(struct swaybar_window *window);
|
||||||
|
|
||||||
void status_in(int fd, short mask, void *data);
|
void status_in(int fd, short mask, void *data);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
bool ipc_initialize(struct swaybar *bar);
|
bool ipc_initialize(struct swaybar *bar);
|
||||||
bool handle_ipc_readable(struct swaybar *bar);
|
bool handle_ipc_readable(struct swaybar *bar);
|
||||||
bool ipc_get_workspaces(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_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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,10 +27,12 @@ struct icon_theme {
|
||||||
char *dir;
|
char *dir;
|
||||||
list_t *subdirs; // struct icon_theme_subdir *
|
list_t *subdirs; // struct icon_theme_subdir *
|
||||||
};
|
};
|
||||||
|
list_t *get_basedirs(void);
|
||||||
void init_themes(list_t **themes, list_t **basedirs);
|
void init_themes(list_t **themes, list_t **basedirs);
|
||||||
void finish_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.
|
* 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 &
|
* 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) {
|
if (e->fullscreen && e->output && e->output->data) {
|
||||||
struct sway_output *output = e->output->data;
|
struct sway_output *output = e->output->data;
|
||||||
struct sway_workspace *ws = output_get_active_workspace(output);
|
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)) {
|
if (container_is_floating(container)) {
|
||||||
workspace_add_floating(ws, container);
|
workspace_add_floating(ws, container);
|
||||||
} else {
|
} 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) {
|
static void swaybar_output_free(struct swaybar_output *output) {
|
||||||
if (!output) {
|
if (!output) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -455,6 +466,7 @@ bool bar_setup(struct swaybar *bar, const char *socket_path) {
|
||||||
if (bar->config->workspace_buttons) {
|
if (bar->config->workspace_buttons) {
|
||||||
ipc_get_workspaces(bar);
|
ipc_get_workspaces(bar);
|
||||||
}
|
}
|
||||||
|
ipc_set_focused_window(bar);
|
||||||
determine_bar_visibility(bar, false);
|
determine_bar_visibility(bar, false);
|
||||||
return true;
|
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 <string.h>
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
#include <json.h>
|
#include <json.h>
|
||||||
|
#include <assert.h>
|
||||||
#include "swaybar/config.h"
|
#include "swaybar/config.h"
|
||||||
#include "swaybar/ipc.h"
|
#include "swaybar/ipc.h"
|
||||||
#include "swaybar/status_line.h"
|
#include "swaybar/status_line.h"
|
||||||
#if HAVE_TRAY
|
#if HAVE_TRAY
|
||||||
#include "swaybar/tray/tray.h"
|
#include "swaybar/tray/tray.h"
|
||||||
#endif
|
#endif
|
||||||
|
#include "desktop.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "swaybar/tray/icon.h"
|
||||||
#include "ipc-client.h"
|
#include "ipc-client.h"
|
||||||
|
#include "background-image.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "loop.h"
|
#include "loop.h"
|
||||||
|
|
@ -427,7 +431,7 @@ 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\", \"window\" %s %s ]",
|
||||||
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,
|
||||||
|
|
@ -541,6 +545,112 @@ static bool handle_barconfig_update(struct swaybar *bar, const char *payload,
|
||||||
return true;
|
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) {
|
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) {
|
||||||
|
|
@ -571,7 +681,10 @@ 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_WORKSPACE:
|
case IPC_EVENT_WORKSPACE:
|
||||||
|
bar->workspace_changed = true;
|
||||||
bar_is_dirty = ipc_get_workspaces(bar);
|
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;
|
break;
|
||||||
case IPC_EVENT_MODE: {
|
case IPC_EVENT_MODE: {
|
||||||
json_object *json_change, *json_pango_markup;
|
json_object *json_change, *json_pango_markup;
|
||||||
|
|
@ -598,6 +711,9 @@ bool handle_ipc_readable(struct swaybar *bar) {
|
||||||
case IPC_EVENT_BAR_STATE_UPDATE:
|
case IPC_EVENT_BAR_STATE_UPDATE:
|
||||||
bar_is_dirty = handle_bar_state_update(bar, result);
|
bar_is_dirty = handle_bar_state_update(bar, result);
|
||||||
break;
|
break;
|
||||||
|
case IPC_EVENT_WINDOW:
|
||||||
|
bar_is_dirty = ipc_set_focused_window(bar);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
bar_is_dirty = false;
|
bar_is_dirty = false;
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ executable(
|
||||||
'main.c',
|
'main.c',
|
||||||
'render.c',
|
'render.c',
|
||||||
'status_line.c',
|
'status_line.c',
|
||||||
|
'desktop.c',
|
||||||
tray_files
|
tray_files
|
||||||
],
|
],
|
||||||
include_directories: [sway_inc],
|
include_directories: [sway_inc],
|
||||||
|
|
|
||||||
147
swaybar/render.c
147
swaybar/render.c
|
|
@ -14,6 +14,9 @@
|
||||||
#include "swaybar/ipc.h"
|
#include "swaybar/ipc.h"
|
||||||
#include "swaybar/render.h"
|
#include "swaybar/render.h"
|
||||||
#include "swaybar/status_line.h"
|
#include "swaybar/status_line.h"
|
||||||
|
#include "swaybar/tray/icon.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "background-image.h"
|
||||||
#if HAVE_TRAY
|
#if HAVE_TRAY
|
||||||
#include "swaybar/tray/tray.h"
|
#include "swaybar/tray/tray.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -121,6 +124,51 @@ static uint32_t render_status_line_text(struct render_context *ctx, double *x) {
|
||||||
return output->height;
|
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,
|
static void render_sharp_rectangle(cairo_t *cairo, uint32_t color,
|
||||||
double x, double y, double width, double height) {
|
double x, double y, double width, double height) {
|
||||||
cairo_save(cairo);
|
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,
|
static uint32_t render_binding_mode_indicator(struct render_context *ctx,
|
||||||
double x) {
|
double *x) {
|
||||||
struct swaybar_output *output = ctx->output;
|
struct swaybar_output *output = ctx->output;
|
||||||
const char *mode = output->bar->mode;
|
const char *mode = output->bar->mode;
|
||||||
if (!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_operator(cairo, CAIRO_OPERATOR_SOURCE);
|
||||||
cairo_set_source_u32(cairo, config->colors.binding_mode.background);
|
cairo_set_source_u32(cairo, config->colors.binding_mode.background);
|
||||||
ctx->background_color = 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_fill(cairo);
|
||||||
|
|
||||||
cairo_set_source_u32(cairo, config->colors.binding_mode.border);
|
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_fill(cairo);
|
||||||
cairo_rectangle(cairo, x, 0, border_width, height);
|
cairo_rectangle(cairo, *x, 0, border_width, height);
|
||||||
cairo_fill(cairo);
|
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_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);
|
cairo_fill(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));
|
||||||
choose_text_aa_mode(ctx, config->colors.binding_mode.text);
|
choose_text_aa_mode(ctx, config->colors.binding_mode.text);
|
||||||
pango_printf(cairo, config->font, output->scale,
|
pango_printf(cairo, config->font, output->scale,
|
||||||
output->bar->mode_pango_markup, "%s", mode);
|
output->bar->mode_pango_markup, "%s", mode);
|
||||||
|
|
||||||
|
*x += width;
|
||||||
|
|
||||||
return output->height;
|
return output->height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -681,6 +732,76 @@ static uint32_t render_workspace_button(struct render_context *ctx,
|
||||||
return output->height;
|
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) {
|
static uint32_t render_to_cairo(struct render_context *ctx) {
|
||||||
cairo_t *cairo = ctx->cairo;
|
cairo_t *cairo = ctx->cairo;
|
||||||
struct swaybar_output *output = ctx->output;
|
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);
|
uint32_t h = render_status_line(ctx, &x);
|
||||||
max_height = h > max_height ? h : max_height;
|
max_height = h > max_height ? h : max_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double old_x = x;
|
||||||
x = 0;
|
x = 0;
|
||||||
if (config->workspace_buttons) {
|
if (config->workspace_buttons) {
|
||||||
struct swaybar_workspace *ws;
|
struct swaybar_workspace *ws;
|
||||||
|
|
@ -726,7 +849,15 @@ static uint32_t render_to_cairo(struct render_context *ctx) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (config->binding_mode_indicator) {
|
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;
|
max_height = h > max_height ? h : max_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
#define _POSIX_C_SOURCE 200809L
|
#define _POSIX_C_SOURCE 200809L
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <assert.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
@ -23,7 +24,25 @@ static bool dir_exists(char *path) {
|
||||||
return stat(path, &sb) == 0 && S_ISDIR(sb.st_mode);
|
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_t *basedirs = create_list();
|
||||||
list_add(basedirs, strdup("$HOME/.icons")); // deprecated
|
list_add(basedirs, strdup("$HOME/.icons")); // deprecated
|
||||||
|
|
||||||
|
|
@ -40,9 +59,7 @@ static list_t *get_basedirs(void) {
|
||||||
data_dirs = strdup(data_dirs);
|
data_dirs = strdup(data_dirs);
|
||||||
char *dir = strtok(data_dirs, ":");
|
char *dir = strtok(data_dirs, ":");
|
||||||
do {
|
do {
|
||||||
size_t path_len = snprintf(NULL, 0, "%s/icons", dir) + 1;
|
char *path = append_path_safe(dir, "icons");
|
||||||
char *path = malloc(path_len);
|
|
||||||
snprintf(path, path_len, "%s/icons", dir);
|
|
||||||
list_add(basedirs, path);
|
list_add(basedirs, path);
|
||||||
} while ((dir = strtok(NULL, ":")));
|
} while ((dir = strtok(NULL, ":")));
|
||||||
free(data_dirs);
|
free(data_dirs);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue