mirror of
https://github.com/swaywm/sway.git
synced 2024-12-27 15:36:29 +01:00
swaybar: implement tray rendering
This commit is contained in:
parent
6b03c68775
commit
fa2c5282c1
3 changed files with 115 additions and 2 deletions
|
@ -1,10 +1,14 @@
|
|||
#ifndef _SWAYBAR_TRAY_ITEM_H
|
||||
#define _SWAYBAR_TRAY_ITEM_H
|
||||
|
||||
#include <cairo.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "swaybar/tray/tray.h"
|
||||
#include "list.h"
|
||||
|
||||
struct swaybar_output;
|
||||
|
||||
struct swaybar_pixmap {
|
||||
int size;
|
||||
unsigned char pixels[];
|
||||
|
@ -34,5 +38,7 @@ struct swaybar_sni {
|
|||
|
||||
struct swaybar_sni *create_sni(char *id, struct swaybar_tray *tray);
|
||||
void destroy_sni(struct swaybar_sni *sni);
|
||||
uint32_t render_sni(cairo_t *cairo, struct swaybar_output *output, double *x,
|
||||
struct swaybar_sni *sni);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,14 +1,27 @@
|
|||
#define _POSIX_C_SOURCE 200809L
|
||||
#include <cairo.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "swaybar/bar.h"
|
||||
#include "swaybar/config.h"
|
||||
#include "swaybar/tray/host.h"
|
||||
#include "swaybar/tray/icon.h"
|
||||
#include "swaybar/tray/item.h"
|
||||
#include "swaybar/tray/tray.h"
|
||||
#include "background-image.h"
|
||||
#include "cairo.h"
|
||||
#include "list.h"
|
||||
#include "log.h"
|
||||
|
||||
// TODO menu
|
||||
|
||||
static bool sni_ready(struct swaybar_sni *sni) {
|
||||
return sni->status && (sni->status[0] == 'N' ?
|
||||
sni->attention_icon_name || sni->attention_icon_pixmap :
|
||||
sni->icon_name || sni->icon_pixmap);
|
||||
}
|
||||
|
||||
static int read_pixmap(sd_bus_message *msg, struct swaybar_sni *sni,
|
||||
const char *prop, list_t **dest) {
|
||||
int ret = sd_bus_message_enter_container(msg, 'a', "(iiay)");
|
||||
|
@ -234,3 +247,74 @@ void destroy_sni(struct swaybar_sni *sni) {
|
|||
free(sni->menu);
|
||||
free(sni);
|
||||
}
|
||||
|
||||
uint32_t render_sni(cairo_t *cairo, struct swaybar_output *output, double *x,
|
||||
struct swaybar_sni *sni) {
|
||||
uint32_t height = output->height * output->scale;
|
||||
int padding = output->bar->config->tray_padding;
|
||||
int ideal_size = height - 2*padding;
|
||||
if ((ideal_size < sni->min_size || ideal_size > sni->max_size) && sni_ready(sni)) {
|
||||
bool icon_found = false;
|
||||
char *icon_name = sni->status[0] == 'N' ?
|
||||
sni->attention_icon_name : sni->icon_name;
|
||||
if (icon_name) {
|
||||
char *icon_path = find_icon(sni->tray->themes, sni->tray->basedirs,
|
||||
icon_name, ideal_size, output->bar->config->icon_theme,
|
||||
&sni->min_size, &sni->max_size);
|
||||
if (icon_path) {
|
||||
cairo_surface_destroy(sni->icon);
|
||||
sni->icon = load_background_image(icon_path);
|
||||
free(icon_path);
|
||||
icon_found = true;
|
||||
}
|
||||
}
|
||||
if (!icon_found) {
|
||||
list_t *pixmaps = sni->status[0] == 'N' ?
|
||||
sni->attention_icon_pixmap : sni->icon_pixmap;
|
||||
if (pixmaps) {
|
||||
int idx = -1;
|
||||
unsigned smallest_error = -1; // UINT_MAX
|
||||
for (int i = 0; i < pixmaps->length; ++i) {
|
||||
struct swaybar_pixmap *pixmap = pixmaps->items[i];
|
||||
unsigned error = (ideal_size - pixmap->size) *
|
||||
(ideal_size < pixmap->size ? -1 : 1);
|
||||
if (error < smallest_error) {
|
||||
smallest_error = error;
|
||||
idx = i;
|
||||
}
|
||||
}
|
||||
struct swaybar_pixmap *pixmap = pixmaps->items[idx];
|
||||
cairo_surface_destroy(sni->icon);
|
||||
sni->icon = cairo_image_surface_create_for_data(pixmap->pixels,
|
||||
CAIRO_FORMAT_ARGB32, pixmap->size, pixmap->size,
|
||||
cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, pixmap->size));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!sni->icon) {
|
||||
// TODO fallback
|
||||
return 0;
|
||||
}
|
||||
|
||||
cairo_surface_t *icon;
|
||||
int actual_size = cairo_image_surface_get_height(sni->icon);
|
||||
int icon_size = actual_size < ideal_size ?
|
||||
actual_size * (ideal_size / actual_size) : ideal_size;
|
||||
icon = cairo_image_surface_scale(sni->icon, icon_size, icon_size);
|
||||
|
||||
int padded_size = icon_size + 2*padding;
|
||||
*x -= padded_size;
|
||||
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);
|
||||
|
||||
cairo_surface_destroy(icon);
|
||||
|
||||
return output->height;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "swaybar/config.h"
|
||||
#include "swaybar/bar.h"
|
||||
#include "swaybar/tray/icon.h"
|
||||
#include "swaybar/tray/host.h"
|
||||
|
@ -70,6 +71,28 @@ void tray_in(int fd, short mask, void *data) {
|
|||
}
|
||||
}
|
||||
|
||||
uint32_t render_tray(cairo_t *cairo, struct swaybar_output *output, double *x) {
|
||||
return 0; // placeholder
|
||||
static int cmp_output(const void *item, const void *cmp_to) {
|
||||
return strcmp(item, cmp_to);
|
||||
}
|
||||
|
||||
uint32_t render_tray(cairo_t *cairo, struct swaybar_output *output, double *x) {
|
||||
struct swaybar_config *config = output->bar->config;
|
||||
if (config->tray_outputs) {
|
||||
if (list_seq_find(config->tray_outputs, cmp_output, output->name) == -1) {
|
||||
return 0;
|
||||
}
|
||||
} // else display on all
|
||||
|
||||
if ((int) output->height*output->scale <= 2*config->tray_padding) {
|
||||
return 2*config->tray_padding + 1;
|
||||
}
|
||||
|
||||
uint32_t max_height = 0;
|
||||
struct swaybar_tray *tray = output->bar->tray;
|
||||
for (int i = 0; i < tray->items->length; ++i) {
|
||||
uint32_t h = render_sni(cairo, output, x, tray->items->items[i]);
|
||||
max_height = h > max_height ? h : max_height;
|
||||
}
|
||||
|
||||
return max_height;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue