-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Split swaybg into a standalone project
- Loading branch information
Showing
16 changed files
with
1,091 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
build |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
Copyright (c) 2016-2019 Drew DeVault | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy of | ||
this software and associated documentation files (the "Software"), to deal in | ||
the Software without restriction, including without limitation the rights to | ||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies | ||
of the Software, and to permit persons to whom the Software is furnished to do | ||
so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
# swaybg | ||
|
||
swaybg is a wallpaper utility for Wayland compositors. It is compatible with any | ||
Wayland compositor which implements the following Wayland protocols: | ||
|
||
- wlr-layer-shell | ||
- xdg-output | ||
- xdg-shell | ||
|
||
See the man page, `swaybg(1)`, for instructions on using swaybg. | ||
|
||
## Release Signatures | ||
|
||
Releases are signed with [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) | ||
and published [on GitHub](https://github.com/swaywm/swaylock/releases). swaybg | ||
releases are managed independently of sway releases. | ||
|
||
## Installation | ||
|
||
### From Packages | ||
|
||
swaybg is available in many distributions. Try installing the "swaybg" | ||
package for yours. | ||
|
||
If you're interested in packaging swaybg for your distribution, stop by the | ||
IRC channel or shoot an email to sir@cmpwn.com for advice. | ||
|
||
### Compiling from Source | ||
|
||
Install dependencies: | ||
|
||
* meson \* | ||
* wayland | ||
* wayland-protocols \* | ||
* libxkbcommon | ||
* cairo | ||
* gdk-pixbuf2 \*\* | ||
* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (optional: man pages) \* | ||
* git \* | ||
|
||
_\*Compile-time dep_ | ||
|
||
_\*\*optional: required for background images other than PNG_ | ||
|
||
Run these commands: | ||
|
||
meson build | ||
ninja -C build | ||
sudo ninja -C build install |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
#include <assert.h> | ||
#include "background-image.h" | ||
#include "cairo.h" | ||
#include "log.h" | ||
|
||
enum background_mode parse_background_mode(const char *mode) { | ||
if (strcmp(mode, "stretch") == 0) { | ||
return BACKGROUND_MODE_STRETCH; | ||
} else if (strcmp(mode, "fill") == 0) { | ||
return BACKGROUND_MODE_FILL; | ||
} else if (strcmp(mode, "fit") == 0) { | ||
return BACKGROUND_MODE_FIT; | ||
} else if (strcmp(mode, "center") == 0) { | ||
return BACKGROUND_MODE_CENTER; | ||
} else if (strcmp(mode, "tile") == 0) { | ||
return BACKGROUND_MODE_TILE; | ||
} else if (strcmp(mode, "solid_color") == 0) { | ||
return BACKGROUND_MODE_SOLID_COLOR; | ||
} | ||
swaybg_log(LOG_ERROR, "Unsupported background mode: %s", mode); | ||
return BACKGROUND_MODE_INVALID; | ||
} | ||
|
||
cairo_surface_t *load_background_image(const char *path) { | ||
cairo_surface_t *image; | ||
#if HAVE_GDK_PIXBUF | ||
GError *err = NULL; | ||
GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(path, &err); | ||
if (!pixbuf) { | ||
swaybg_log(LOG_ERROR, "Failed to load background image (%s).", | ||
err->message); | ||
return NULL; | ||
} | ||
image = gdk_cairo_image_surface_create_from_pixbuf(pixbuf); | ||
g_object_unref(pixbuf); | ||
#else | ||
image = cairo_image_surface_create_from_png(path); | ||
#endif // HAVE_GDK_PIXBUF | ||
if (!image) { | ||
swaybg_log(LOG_ERROR, "Failed to read background image."); | ||
return NULL; | ||
} | ||
if (cairo_surface_status(image) != CAIRO_STATUS_SUCCESS) { | ||
swaybg_log(LOG_ERROR, "Failed to read background image: %s." | ||
#if !HAVE_GDK_PIXBUF | ||
"\nSway was compiled without gdk_pixbuf support, so only" | ||
"\nPNG images can be loaded. This is the likely cause." | ||
#endif // !HAVE_GDK_PIXBUF | ||
, cairo_status_to_string(cairo_surface_status(image))); | ||
return NULL; | ||
} | ||
return image; | ||
} | ||
|
||
void render_background_image(cairo_t *cairo, cairo_surface_t *image, | ||
enum background_mode mode, int buffer_width, int buffer_height) { | ||
double width = cairo_image_surface_get_width(image); | ||
double height = cairo_image_surface_get_height(image); | ||
|
||
cairo_save(cairo); | ||
switch (mode) { | ||
case BACKGROUND_MODE_STRETCH: | ||
cairo_scale(cairo, | ||
(double)buffer_width / width, | ||
(double)buffer_height / height); | ||
cairo_set_source_surface(cairo, image, 0, 0); | ||
break; | ||
case BACKGROUND_MODE_FILL: { | ||
double window_ratio = (double)buffer_width / buffer_height; | ||
double bg_ratio = width / height; | ||
|
||
if (window_ratio > bg_ratio) { | ||
double scale = (double)buffer_width / width; | ||
cairo_scale(cairo, scale, scale); | ||
cairo_set_source_surface(cairo, image, | ||
0, (double)buffer_height / 2 / scale - height / 2); | ||
} else { | ||
double scale = (double)buffer_height / height; | ||
cairo_scale(cairo, scale, scale); | ||
cairo_set_source_surface(cairo, image, | ||
(double)buffer_width / 2 / scale - width / 2, 0); | ||
} | ||
break; | ||
} | ||
case BACKGROUND_MODE_FIT: { | ||
double window_ratio = (double)buffer_width / buffer_height; | ||
double bg_ratio = width / height; | ||
|
||
if (window_ratio > bg_ratio) { | ||
double scale = (double)buffer_height / height; | ||
cairo_scale(cairo, scale, scale); | ||
cairo_set_source_surface(cairo, image, | ||
(double)buffer_width / 2 / scale - width / 2, 0); | ||
} else { | ||
double scale = (double)buffer_width / width; | ||
cairo_scale(cairo, scale, scale); | ||
cairo_set_source_surface(cairo, image, | ||
0, (double)buffer_height / 2 / scale - height / 2); | ||
} | ||
break; | ||
} | ||
case BACKGROUND_MODE_CENTER: | ||
cairo_set_source_surface(cairo, image, | ||
(double)buffer_width / 2 - width / 2, | ||
(double)buffer_height / 2 - height / 2); | ||
break; | ||
case BACKGROUND_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 BACKGROUND_MODE_SOLID_COLOR: | ||
case BACKGROUND_MODE_INVALID: | ||
assert(0); | ||
break; | ||
} | ||
cairo_paint(cairo); | ||
cairo_restore(cairo); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
#include <stdint.h> | ||
#include <cairo/cairo.h> | ||
#include "cairo.h" | ||
#if HAVE_GDK_PIXBUF | ||
#include <gdk-pixbuf/gdk-pixbuf.h> | ||
#endif | ||
|
||
void cairo_set_source_u32(cairo_t *cairo, uint32_t color) { | ||
cairo_set_source_rgba(cairo, | ||
(color >> (3*8) & 0xFF) / 255.0, | ||
(color >> (2*8) & 0xFF) / 255.0, | ||
(color >> (1*8) & 0xFF) / 255.0, | ||
(color >> (0*8) & 0xFF) / 255.0); | ||
} | ||
|
||
cairo_subpixel_order_t to_cairo_subpixel_order(enum wl_output_subpixel subpixel) { | ||
switch (subpixel) { | ||
case WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB: | ||
return CAIRO_SUBPIXEL_ORDER_RGB; | ||
case WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR: | ||
return CAIRO_SUBPIXEL_ORDER_BGR; | ||
case WL_OUTPUT_SUBPIXEL_VERTICAL_RGB: | ||
return CAIRO_SUBPIXEL_ORDER_VRGB; | ||
case WL_OUTPUT_SUBPIXEL_VERTICAL_BGR: | ||
return CAIRO_SUBPIXEL_ORDER_VBGR; | ||
default: | ||
return CAIRO_SUBPIXEL_ORDER_DEFAULT; | ||
} | ||
return CAIRO_SUBPIXEL_ORDER_DEFAULT; | ||
} | ||
|
||
#if HAVE_GDK_PIXBUF | ||
cairo_surface_t* gdk_cairo_image_surface_create_from_pixbuf(const GdkPixbuf *gdkbuf) { | ||
int chan = gdk_pixbuf_get_n_channels(gdkbuf); | ||
if (chan < 3) { | ||
return NULL; | ||
} | ||
|
||
const guint8* gdkpix = gdk_pixbuf_read_pixels(gdkbuf); | ||
if (!gdkpix) { | ||
return NULL; | ||
} | ||
gint w = gdk_pixbuf_get_width(gdkbuf); | ||
gint h = gdk_pixbuf_get_height(gdkbuf); | ||
int stride = gdk_pixbuf_get_rowstride(gdkbuf); | ||
|
||
cairo_format_t fmt = (chan == 3) ? CAIRO_FORMAT_RGB24 : CAIRO_FORMAT_ARGB32; | ||
cairo_surface_t * cs = cairo_image_surface_create (fmt, w, h); | ||
cairo_surface_flush (cs); | ||
if ( !cs || cairo_surface_status(cs) != CAIRO_STATUS_SUCCESS) { | ||
return NULL; | ||
} | ||
|
||
int cstride = cairo_image_surface_get_stride(cs); | ||
unsigned char * cpix = cairo_image_surface_get_data(cs); | ||
|
||
if (chan == 3) { | ||
int i; | ||
for (i = h; i; --i) { | ||
const guint8 *gp = gdkpix; | ||
unsigned char *cp = cpix; | ||
const guint8* end = gp + 3*w; | ||
while (gp < end) { | ||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN | ||
cp[0] = gp[2]; | ||
cp[1] = gp[1]; | ||
cp[2] = gp[0]; | ||
#else | ||
cp[1] = gp[0]; | ||
cp[2] = gp[1]; | ||
cp[3] = gp[2]; | ||
#endif | ||
gp += 3; | ||
cp += 4; | ||
} | ||
gdkpix += stride; | ||
cpix += cstride; | ||
} | ||
} else { | ||
/* premul-color = alpha/255 * color/255 * 255 = (alpha*color)/255 | ||
* (z/255) = z/256 * 256/255 = z/256 (1 + 1/255) | ||
* = z/256 + (z/256)/255 = (z + z/255)/256 | ||
* # recurse once | ||
* = (z + (z + z/255)/256)/256 | ||
* = (z + z/256 + z/256/255) / 256 | ||
* # only use 16bit uint operations, loose some precision, | ||
* # result is floored. | ||
* -> (z + z>>8)>>8 | ||
* # add 0x80/255 = 0.5 to convert floor to round | ||
* => (z+0x80 + (z+0x80)>>8 ) >> 8 | ||
* ------ | ||
* tested as equal to lround(z/255.0) for uint z in [0..0xfe02] | ||
*/ | ||
#define PREMUL_ALPHA(x,a,b,z) \ | ||
G_STMT_START { z = a * b + 0x80; x = (z + (z >> 8)) >> 8; } \ | ||
G_STMT_END | ||
int i; | ||
for (i = h; i; --i) { | ||
const guint8 *gp = gdkpix; | ||
unsigned char *cp = cpix; | ||
const guint8* end = gp + 4*w; | ||
guint z1, z2, z3; | ||
while (gp < end) { | ||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN | ||
PREMUL_ALPHA(cp[0], gp[2], gp[3], z1); | ||
PREMUL_ALPHA(cp[1], gp[1], gp[3], z2); | ||
PREMUL_ALPHA(cp[2], gp[0], gp[3], z3); | ||
cp[3] = gp[3]; | ||
#else | ||
PREMUL_ALPHA(cp[1], gp[0], gp[3], z1); | ||
PREMUL_ALPHA(cp[2], gp[1], gp[3], z2); | ||
PREMUL_ALPHA(cp[3], gp[2], gp[3], z3); | ||
cp[0] = gp[3]; | ||
#endif | ||
gp += 4; | ||
cp += 4; | ||
} | ||
gdkpix += stride; | ||
cpix += cstride; | ||
} | ||
#undef PREMUL_ALPHA | ||
} | ||
cairo_surface_mark_dirty(cs); | ||
return cs; | ||
} | ||
#endif // HAVE_GDK_PIXBUF |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
#ifndef _SWAY_BACKGROUND_IMAGE_H | ||
#define _SWAY_BACKGROUND_IMAGE_H | ||
#include "cairo.h" | ||
|
||
enum background_mode { | ||
BACKGROUND_MODE_STRETCH, | ||
BACKGROUND_MODE_FILL, | ||
BACKGROUND_MODE_FIT, | ||
BACKGROUND_MODE_CENTER, | ||
BACKGROUND_MODE_TILE, | ||
BACKGROUND_MODE_SOLID_COLOR, | ||
BACKGROUND_MODE_INVALID, | ||
}; | ||
|
||
enum background_mode parse_background_mode(const char *mode); | ||
cairo_surface_t *load_background_image(const char *path); | ||
void render_background_image(cairo_t *cairo, cairo_surface_t *image, | ||
enum background_mode mode, int buffer_width, int buffer_height); | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
#ifndef _SWAY_CAIRO_H | ||
#define _SWAY_CAIRO_H | ||
|
||
#include "config.h" | ||
#include <stdint.h> | ||
#include <cairo/cairo.h> | ||
#include <wayland-client.h> | ||
#if HAVE_GDK_PIXBUF | ||
#include <gdk-pixbuf/gdk-pixbuf.h> | ||
#endif | ||
|
||
void cairo_set_source_u32(cairo_t *cairo, uint32_t color); | ||
cairo_subpixel_order_t to_cairo_subpixel_order(enum wl_output_subpixel subpixel); | ||
|
||
cairo_surface_t *cairo_image_surface_scale(cairo_surface_t *image, | ||
int width, int height); | ||
|
||
#if HAVE_GDK_PIXBUF | ||
|
||
cairo_surface_t* gdk_cairo_image_surface_create_from_pixbuf( | ||
const GdkPixbuf *gdkbuf); | ||
|
||
#endif // HAVE_GDK_PIXBUF | ||
|
||
#endif |
Oops, something went wrong.