mirror of
https://github.com/swaywm/sway.git
synced 2024-11-25 09:21:28 +00:00
Implement image backgrounds
This commit is contained in:
parent
632bb948b7
commit
f018d30fe4
114
swaybg/main.c
114
swaybg/main.c
|
@ -26,8 +26,14 @@ struct swaybg_args {
|
|||
enum scaling_mode mode;
|
||||
};
|
||||
|
||||
struct swaybg_context {
|
||||
uint32_t color;
|
||||
cairo_surface_t *image;
|
||||
};
|
||||
|
||||
struct swaybg_state {
|
||||
const struct swaybg_args *args;
|
||||
struct swaybg_context context;
|
||||
|
||||
struct wl_display *display;
|
||||
struct wl_compositor *compositor;
|
||||
|
@ -62,6 +68,71 @@ bool is_valid_color(const char *color) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static void render_image(struct swaybg_state *state) {
|
||||
cairo_t *cairo = state->current_buffer->cairo;
|
||||
cairo_surface_t *image = state->context.image;
|
||||
double width = cairo_image_surface_get_width(image);
|
||||
double height = cairo_image_surface_get_height(image);
|
||||
int wwidth = state->width;
|
||||
int wheight = state->height;
|
||||
|
||||
switch (state->args->mode) {
|
||||
case SCALING_MODE_STRETCH:
|
||||
cairo_scale(cairo, (double)wwidth / width, (double)wheight / height);
|
||||
cairo_set_source_surface(cairo, image, 0, 0);
|
||||
break;
|
||||
case SCALING_MODE_FILL: {
|
||||
double window_ratio = (double)wwidth / wheight;
|
||||
double bg_ratio = width / height;
|
||||
|
||||
if (window_ratio > bg_ratio) {
|
||||
double scale = (double)wwidth / width;
|
||||
cairo_scale(cairo, scale, scale);
|
||||
cairo_set_source_surface(cairo, image,
|
||||
0, (double)wheight / 2 / scale - height / 2);
|
||||
} else {
|
||||
double scale = (double)wheight / height;
|
||||
cairo_scale(cairo, scale, scale);
|
||||
cairo_set_source_surface(cairo, image,
|
||||
(double)wwidth / 2 / scale - width / 2, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SCALING_MODE_FIT: {
|
||||
double window_ratio = (double)wwidth / wheight;
|
||||
double bg_ratio = width / height;
|
||||
|
||||
if (window_ratio > bg_ratio) {
|
||||
double scale = (double)wheight / height;
|
||||
cairo_scale(cairo, scale, scale);
|
||||
cairo_set_source_surface(cairo, image,
|
||||
(double)wwidth / 2 / scale - width / 2, 0);
|
||||
} else {
|
||||
double scale = (double)wwidth / width;
|
||||
cairo_scale(cairo, scale, scale);
|
||||
cairo_set_source_surface(cairo, image,
|
||||
0, (double)wheight / 2 / scale - height / 2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SCALING_MODE_CENTER:
|
||||
cairo_set_source_surface(cairo, image,
|
||||
(double)wwidth / 2 - width / 2,
|
||||
(double)wheight / 2 - height / 2);
|
||||
break;
|
||||
case SCALING_MODE_TILE: {
|
||||
cairo_pattern_t *pattern = cairo_pattern_create_for_surface(image);
|
||||
cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
|
||||
cairo_set_source(cairo, pattern);
|
||||
break;
|
||||
}
|
||||
case SCALING_MODE_SOLID_COLOR:
|
||||
// Should never happen
|
||||
break;
|
||||
}
|
||||
cairo_paint(cairo);
|
||||
}
|
||||
|
||||
static void render_frame(struct swaybg_state *state) {
|
||||
if (!state->run_display) {
|
||||
return;
|
||||
|
@ -73,11 +144,11 @@ static void render_frame(struct swaybg_state *state) {
|
|||
|
||||
switch (state->args->mode) {
|
||||
case SCALING_MODE_SOLID_COLOR:
|
||||
cairo_set_source_u32(cairo, parse_color(state->args->path));
|
||||
cairo_set_source_u32(cairo, state->context.color);
|
||||
cairo_paint(cairo);
|
||||
break;
|
||||
default:
|
||||
exit(1);
|
||||
render_image(state);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -86,6 +157,41 @@ static void render_frame(struct swaybg_state *state) {
|
|||
wl_surface_commit(state->surface);
|
||||
}
|
||||
|
||||
static bool prepare_context(struct swaybg_state *state) {
|
||||
if (state->args->mode == SCALING_MODE_SOLID_COLOR) {
|
||||
state->context.color = parse_color(state->args->path);
|
||||
return is_valid_color(state->args->path);
|
||||
}
|
||||
#ifdef WITH_GDK_PIXBUF
|
||||
GError *err = NULL;
|
||||
GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(state->args->path, &err);
|
||||
if (!pixbuf) {
|
||||
wlr_log(L_ERROR, "Failed to load background image.");
|
||||
return false;
|
||||
}
|
||||
state->context.image = gdk_cairo_image_surface_create_from_pixbuf(pixbuf);
|
||||
g_object_unref(pixbuf);
|
||||
#else
|
||||
state->context.image = cairo_image_surface_create_from_png(
|
||||
state->args->path);
|
||||
#endif //WITH_GDK_PIXBUF
|
||||
if (!state->context.image) {
|
||||
wlr_log(L_ERROR, "Failed to read background image.");
|
||||
return false;
|
||||
}
|
||||
if (cairo_surface_status(state->context.image) != CAIRO_STATUS_SUCCESS) {
|
||||
wlr_log(L_ERROR, "Failed to read background image: %s."
|
||||
#ifndef WITH_GDK_PIXBUF
|
||||
"\nSway was compiled without gdk_pixbuf support, so only"
|
||||
"\nPNG images can be loaded. This is the likely cause."
|
||||
#endif //WITH_GDK_PIXBUF
|
||||
, cairo_status_to_string(
|
||||
cairo_surface_status(state->context.image)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void layer_surface_configure(void *data,
|
||||
struct zwlr_layer_surface_v1 *surface,
|
||||
uint32_t serial, uint32_t width, uint32_t height) {
|
||||
|
@ -217,6 +323,10 @@ int main(int argc, const char **argv) {
|
|||
wl_surface_commit(state.surface);
|
||||
wl_display_roundtrip(state.display);
|
||||
|
||||
if (!prepare_context(&state)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
state.run_display = true;
|
||||
render_frame(&state);
|
||||
while (wl_display_dispatch(state.display) != -1 && state.run_display) {
|
||||
|
|
Loading…
Reference in a new issue