2015-09-05 23:38:15 +02:00
|
|
|
/*
|
|
|
|
* vim:ts=4:sw=4:expandtab
|
|
|
|
*
|
|
|
|
* © 2015 Ingo Bürk and contributors (see also: LICENSE)
|
|
|
|
*
|
2015-10-14 20:49:52 +02:00
|
|
|
* draw.c: Utility for drawing.
|
2015-09-05 23:38:15 +02:00
|
|
|
*
|
|
|
|
*/
|
2016-10-11 09:13:35 +02:00
|
|
|
#include "libi3.h"
|
|
|
|
|
2015-09-05 23:38:15 +02:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <err.h>
|
2015-10-05 12:58:05 +02:00
|
|
|
#include <string.h>
|
2015-09-05 23:38:15 +02:00
|
|
|
#include <xcb/xcb.h>
|
|
|
|
#include <xcb/xcb_aux.h>
|
|
|
|
#include <cairo/cairo-xcb.h>
|
|
|
|
|
Migrate i3 rendering to cairo.
This patch migrates all decoration rendering of i3 to cairo. Using the
compile switch CAIRO_SUPPORT, rendering can be switched back to the
previous XCB behavior, just like with the previous migration to cairo
in i3bar.
This patch also fixes a bug in draw_util.c where copying one surface
to another would use incorrect coordinates if the source coordinates
are not 0, 0.
Furthermore, this patch implicitly fixes some minor issues in the
decoration rendering which would be ignored previously due to the fact
that errors would only show up in the event queue, but not cause the
rendering code path to crash. One example is zero-height pixmaps which
are not allowed. Using cairo, these would cause i3 to instantly segfault,
so this patch avoids this.
Lastly, this patch annotates other issues found but not fixed in this patch
using TODO comments, e.g., the zero-height check not working correctly
and the comment that it should probably work the same way for zero-width
pixmaps.
relates to #1278
2015-11-16 21:26:06 +01:00
|
|
|
/* The default visual_type to use if none is specified when creating the surface. Must be defined globally. */
|
2015-10-05 12:58:05 +02:00
|
|
|
xcb_visualtype_t *visual_type;
|
2015-09-05 23:38:15 +02:00
|
|
|
|
2015-10-14 20:49:52 +02:00
|
|
|
/* Forward declarations */
|
2017-01-13 18:34:09 +01:00
|
|
|
static void draw_util_set_source_color(surface_t *surface, color_t color);
|
2015-10-14 20:49:52 +02:00
|
|
|
|
2015-11-16 21:28:33 +01:00
|
|
|
#define RETURN_UNLESS_SURFACE_INITIALIZED(surface) \
|
|
|
|
do { \
|
|
|
|
if ((surface)->id == XCB_NONE) { \
|
|
|
|
ELOG("Surface %p is not initialized, skipping drawing.\n", surface); \
|
|
|
|
return; \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
2015-09-05 23:38:15 +02:00
|
|
|
/*
|
2015-10-14 20:49:52 +02:00
|
|
|
* Initialize the surface to represent the given drawable.
|
2015-09-05 23:38:15 +02:00
|
|
|
*
|
|
|
|
*/
|
Migrate i3 rendering to cairo.
This patch migrates all decoration rendering of i3 to cairo. Using the
compile switch CAIRO_SUPPORT, rendering can be switched back to the
previous XCB behavior, just like with the previous migration to cairo
in i3bar.
This patch also fixes a bug in draw_util.c where copying one surface
to another would use incorrect coordinates if the source coordinates
are not 0, 0.
Furthermore, this patch implicitly fixes some minor issues in the
decoration rendering which would be ignored previously due to the fact
that errors would only show up in the event queue, but not cause the
rendering code path to crash. One example is zero-height pixmaps which
are not allowed. Using cairo, these would cause i3 to instantly segfault,
so this patch avoids this.
Lastly, this patch annotates other issues found but not fixed in this patch
using TODO comments, e.g., the zero-height check not working correctly
and the comment that it should probably work the same way for zero-width
pixmaps.
relates to #1278
2015-11-16 21:26:06 +01:00
|
|
|
void draw_util_surface_init(xcb_connection_t *conn, surface_t *surface, xcb_drawable_t drawable,
|
|
|
|
xcb_visualtype_t *visual, int width, int height) {
|
2015-09-05 23:38:15 +02:00
|
|
|
surface->id = drawable;
|
2015-11-17 12:50:06 +01:00
|
|
|
surface->visual_type = ((visual == NULL) ? visual_type : visual);
|
2015-10-14 20:49:52 +02:00
|
|
|
surface->width = width;
|
|
|
|
surface->height = height;
|
2015-09-05 23:38:15 +02:00
|
|
|
|
Migrate i3 rendering to cairo.
This patch migrates all decoration rendering of i3 to cairo. Using the
compile switch CAIRO_SUPPORT, rendering can be switched back to the
previous XCB behavior, just like with the previous migration to cairo
in i3bar.
This patch also fixes a bug in draw_util.c where copying one surface
to another would use incorrect coordinates if the source coordinates
are not 0, 0.
Furthermore, this patch implicitly fixes some minor issues in the
decoration rendering which would be ignored previously due to the fact
that errors would only show up in the event queue, but not cause the
rendering code path to crash. One example is zero-height pixmaps which
are not allowed. Using cairo, these would cause i3 to instantly segfault,
so this patch avoids this.
Lastly, this patch annotates other issues found but not fixed in this patch
using TODO comments, e.g., the zero-height check not working correctly
and the comment that it should probably work the same way for zero-width
pixmaps.
relates to #1278
2015-11-16 21:26:06 +01:00
|
|
|
surface->gc = xcb_generate_id(conn);
|
|
|
|
xcb_void_cookie_t gc_cookie = xcb_create_gc_checked(conn, surface->gc, surface->id, 0, NULL);
|
2015-11-11 23:39:15 +01:00
|
|
|
|
Migrate i3 rendering to cairo.
This patch migrates all decoration rendering of i3 to cairo. Using the
compile switch CAIRO_SUPPORT, rendering can be switched back to the
previous XCB behavior, just like with the previous migration to cairo
in i3bar.
This patch also fixes a bug in draw_util.c where copying one surface
to another would use incorrect coordinates if the source coordinates
are not 0, 0.
Furthermore, this patch implicitly fixes some minor issues in the
decoration rendering which would be ignored previously due to the fact
that errors would only show up in the event queue, but not cause the
rendering code path to crash. One example is zero-height pixmaps which
are not allowed. Using cairo, these would cause i3 to instantly segfault,
so this patch avoids this.
Lastly, this patch annotates other issues found but not fixed in this patch
using TODO comments, e.g., the zero-height check not working correctly
and the comment that it should probably work the same way for zero-width
pixmaps.
relates to #1278
2015-11-16 21:26:06 +01:00
|
|
|
xcb_generic_error_t *error = xcb_request_check(conn, gc_cookie);
|
2015-11-11 23:39:15 +01:00
|
|
|
if (error != NULL) {
|
2015-12-03 18:59:35 +01:00
|
|
|
ELOG("Could not create graphical context. Error code: %d. Please report this bug.\n", error->error_code);
|
2015-11-11 23:39:15 +01:00
|
|
|
}
|
2015-09-05 23:38:15 +02:00
|
|
|
|
Migrate i3 rendering to cairo.
This patch migrates all decoration rendering of i3 to cairo. Using the
compile switch CAIRO_SUPPORT, rendering can be switched back to the
previous XCB behavior, just like with the previous migration to cairo
in i3bar.
This patch also fixes a bug in draw_util.c where copying one surface
to another would use incorrect coordinates if the source coordinates
are not 0, 0.
Furthermore, this patch implicitly fixes some minor issues in the
decoration rendering which would be ignored previously due to the fact
that errors would only show up in the event queue, but not cause the
rendering code path to crash. One example is zero-height pixmaps which
are not allowed. Using cairo, these would cause i3 to instantly segfault,
so this patch avoids this.
Lastly, this patch annotates other issues found but not fixed in this patch
using TODO comments, e.g., the zero-height check not working correctly
and the comment that it should probably work the same way for zero-width
pixmaps.
relates to #1278
2015-11-16 21:26:06 +01:00
|
|
|
surface->surface = cairo_xcb_surface_create(conn, surface->id, surface->visual_type, width, height);
|
2015-09-05 23:38:15 +02:00
|
|
|
surface->cr = cairo_create(surface->surface);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Destroys the surface.
|
|
|
|
*
|
|
|
|
*/
|
Migrate i3 rendering to cairo.
This patch migrates all decoration rendering of i3 to cairo. Using the
compile switch CAIRO_SUPPORT, rendering can be switched back to the
previous XCB behavior, just like with the previous migration to cairo
in i3bar.
This patch also fixes a bug in draw_util.c where copying one surface
to another would use incorrect coordinates if the source coordinates
are not 0, 0.
Furthermore, this patch implicitly fixes some minor issues in the
decoration rendering which would be ignored previously due to the fact
that errors would only show up in the event queue, but not cause the
rendering code path to crash. One example is zero-height pixmaps which
are not allowed. Using cairo, these would cause i3 to instantly segfault,
so this patch avoids this.
Lastly, this patch annotates other issues found but not fixed in this patch
using TODO comments, e.g., the zero-height check not working correctly
and the comment that it should probably work the same way for zero-width
pixmaps.
relates to #1278
2015-11-16 21:26:06 +01:00
|
|
|
void draw_util_surface_free(xcb_connection_t *conn, surface_t *surface) {
|
|
|
|
xcb_free_gc(conn, surface->gc);
|
2015-09-05 23:38:15 +02:00
|
|
|
cairo_surface_destroy(surface->surface);
|
|
|
|
cairo_destroy(surface->cr);
|
2015-11-18 15:32:45 +01:00
|
|
|
|
|
|
|
/* We need to explicitly set these to NULL to avoid assertion errors in
|
|
|
|
* cairo when calling this multiple times. This can happen, for example,
|
|
|
|
* when setting the border of a window to none and then closing it. */
|
|
|
|
surface->surface = NULL;
|
|
|
|
surface->cr = NULL;
|
2015-09-05 23:38:15 +02:00
|
|
|
}
|
|
|
|
|
Migrate i3 rendering to cairo.
This patch migrates all decoration rendering of i3 to cairo. Using the
compile switch CAIRO_SUPPORT, rendering can be switched back to the
previous XCB behavior, just like with the previous migration to cairo
in i3bar.
This patch also fixes a bug in draw_util.c where copying one surface
to another would use incorrect coordinates if the source coordinates
are not 0, 0.
Furthermore, this patch implicitly fixes some minor issues in the
decoration rendering which would be ignored previously due to the fact
that errors would only show up in the event queue, but not cause the
rendering code path to crash. One example is zero-height pixmaps which
are not allowed. Using cairo, these would cause i3 to instantly segfault,
so this patch avoids this.
Lastly, this patch annotates other issues found but not fixed in this patch
using TODO comments, e.g., the zero-height check not working correctly
and the comment that it should probably work the same way for zero-width
pixmaps.
relates to #1278
2015-11-16 21:26:06 +01:00
|
|
|
/*
|
|
|
|
* Resize the surface to the given size.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
void draw_util_surface_set_size(surface_t *surface, int width, int height) {
|
|
|
|
surface->width = width;
|
|
|
|
surface->height = height;
|
|
|
|
cairo_xcb_surface_set_size(surface->surface, width, height);
|
|
|
|
}
|
|
|
|
|
2015-09-05 23:38:15 +02:00
|
|
|
/*
|
|
|
|
* Parses the given color in hex format to an internal color representation.
|
|
|
|
* Note that the input must begin with a hash sign, e.g., "#3fbc59".
|
|
|
|
*
|
|
|
|
*/
|
2015-10-14 20:49:52 +02:00
|
|
|
color_t draw_util_hex_to_color(const char *color) {
|
2017-07-12 23:50:19 +02:00
|
|
|
if (strlen(color) < 6 || color[0] != '#') {
|
|
|
|
ELOG("Could not parse color: %s\n", color);
|
|
|
|
return draw_util_hex_to_color("#A9A9A9");
|
|
|
|
}
|
|
|
|
|
2015-11-17 12:50:06 +01:00
|
|
|
char alpha[2];
|
|
|
|
if (strlen(color) == strlen("#rrggbbaa")) {
|
|
|
|
alpha[0] = color[7];
|
|
|
|
alpha[1] = color[8];
|
|
|
|
} else {
|
|
|
|
alpha[0] = alpha[1] = 'F';
|
|
|
|
}
|
|
|
|
|
|
|
|
char groups[4][3] = {
|
2015-09-05 23:38:15 +02:00
|
|
|
{color[1], color[2], '\0'},
|
|
|
|
{color[3], color[4], '\0'},
|
2015-11-17 12:50:06 +01:00
|
|
|
{color[5], color[6], '\0'},
|
|
|
|
{alpha[0], alpha[1], '\0'}};
|
2015-09-05 23:38:15 +02:00
|
|
|
|
|
|
|
return (color_t){
|
|
|
|
.red = strtol(groups[0], NULL, 16) / 255.0,
|
|
|
|
.green = strtol(groups[1], NULL, 16) / 255.0,
|
|
|
|
.blue = strtol(groups[2], NULL, 16) / 255.0,
|
2015-11-17 12:50:06 +01:00
|
|
|
.alpha = strtol(groups[3], NULL, 16) / 255.0,
|
2015-09-05 23:38:15 +02:00
|
|
|
.colorpixel = get_colorpixel(color)};
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set the given color as the source color on the surface.
|
|
|
|
*
|
|
|
|
*/
|
2017-01-13 18:34:09 +01:00
|
|
|
static void draw_util_set_source_color(surface_t *surface, color_t color) {
|
2015-11-16 21:28:33 +01:00
|
|
|
RETURN_UNLESS_SURFACE_INITIALIZED(surface);
|
|
|
|
|
2015-11-17 12:50:06 +01:00
|
|
|
cairo_set_source_rgba(surface->cr, color.red, color.green, color.blue, color.alpha);
|
2015-09-05 23:38:15 +02:00
|
|
|
}
|
2015-10-08 12:16:25 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Draw the given text using libi3.
|
|
|
|
* This function also marks the surface dirty which is needed if other means of
|
|
|
|
* drawing are used. This will be the case when using XCB to draw text.
|
|
|
|
*
|
|
|
|
*/
|
2015-10-14 20:49:52 +02:00
|
|
|
void draw_util_text(i3String *text, surface_t *surface, color_t fg_color, color_t bg_color, int x, int y, int max_width) {
|
2015-11-16 21:28:33 +01:00
|
|
|
RETURN_UNLESS_SURFACE_INITIALIZED(surface);
|
|
|
|
|
2015-10-13 11:08:10 +02:00
|
|
|
/* Flush any changes before we draw the text as this might use XCB directly. */
|
2015-10-14 18:57:16 +02:00
|
|
|
CAIRO_SURFACE_FLUSH(surface->surface);
|
2015-10-13 11:08:10 +02:00
|
|
|
|
2015-12-28 12:43:53 +01:00
|
|
|
set_font_colors(surface->gc, fg_color, bg_color);
|
Migrate i3 rendering to cairo.
This patch migrates all decoration rendering of i3 to cairo. Using the
compile switch CAIRO_SUPPORT, rendering can be switched back to the
previous XCB behavior, just like with the previous migration to cairo
in i3bar.
This patch also fixes a bug in draw_util.c where copying one surface
to another would use incorrect coordinates if the source coordinates
are not 0, 0.
Furthermore, this patch implicitly fixes some minor issues in the
decoration rendering which would be ignored previously due to the fact
that errors would only show up in the event queue, but not cause the
rendering code path to crash. One example is zero-height pixmaps which
are not allowed. Using cairo, these would cause i3 to instantly segfault,
so this patch avoids this.
Lastly, this patch annotates other issues found but not fixed in this patch
using TODO comments, e.g., the zero-height check not working correctly
and the comment that it should probably work the same way for zero-width
pixmaps.
relates to #1278
2015-11-16 21:26:06 +01:00
|
|
|
draw_text(text, surface->id, surface->gc, surface->visual_type, x, y, max_width);
|
2015-10-08 12:16:25 +02:00
|
|
|
|
2015-10-13 11:08:10 +02:00
|
|
|
/* Notify cairo that we (possibly) used another way to draw on the surface. */
|
2015-10-08 12:16:25 +02:00
|
|
|
cairo_surface_mark_dirty(surface->surface);
|
|
|
|
}
|
2015-10-08 12:31:56 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Draws a filled rectangle.
|
|
|
|
* This function is a convenience wrapper and takes care of flushing the
|
|
|
|
* surface as well as restoring the cairo state.
|
|
|
|
*
|
|
|
|
*/
|
2017-01-13 18:34:09 +01:00
|
|
|
void draw_util_rectangle(surface_t *surface, color_t color, double x, double y, double w, double h) {
|
2015-11-16 21:28:33 +01:00
|
|
|
RETURN_UNLESS_SURFACE_INITIALIZED(surface);
|
|
|
|
|
2015-10-08 12:31:56 +02:00
|
|
|
cairo_save(surface->cr);
|
|
|
|
|
|
|
|
/* Using the SOURCE operator will copy both color and alpha information directly
|
|
|
|
* onto the surface rather than blending it. This is a bit more efficient and
|
|
|
|
* allows better color control for the user when using opacity. */
|
|
|
|
cairo_set_operator(surface->cr, CAIRO_OPERATOR_SOURCE);
|
2017-01-13 18:34:09 +01:00
|
|
|
draw_util_set_source_color(surface, color);
|
2015-10-08 12:31:56 +02:00
|
|
|
|
|
|
|
cairo_rectangle(surface->cr, x, y, w, h);
|
|
|
|
cairo_fill(surface->cr);
|
|
|
|
|
|
|
|
/* Make sure we flush the surface for any text drawing operations that could follow.
|
|
|
|
* Since we support drawing text via XCB, we need this. */
|
2015-10-14 18:57:16 +02:00
|
|
|
CAIRO_SURFACE_FLUSH(surface->surface);
|
2015-10-08 12:31:56 +02:00
|
|
|
|
|
|
|
cairo_restore(surface->cr);
|
|
|
|
}
|
|
|
|
|
2015-10-14 19:03:05 +02:00
|
|
|
/**
|
|
|
|
* Clears a surface with the given color.
|
|
|
|
*
|
|
|
|
*/
|
2017-01-13 18:34:09 +01:00
|
|
|
void draw_util_clear_surface(surface_t *surface, color_t color) {
|
2015-11-16 21:28:33 +01:00
|
|
|
RETURN_UNLESS_SURFACE_INITIALIZED(surface);
|
|
|
|
|
2015-10-14 19:03:05 +02:00
|
|
|
cairo_save(surface->cr);
|
|
|
|
|
|
|
|
/* Using the SOURCE operator will copy both color and alpha information directly
|
|
|
|
* onto the surface rather than blending it. This is a bit more efficient and
|
|
|
|
* allows better color control for the user when using opacity. */
|
|
|
|
cairo_set_operator(surface->cr, CAIRO_OPERATOR_SOURCE);
|
2017-01-13 18:34:09 +01:00
|
|
|
draw_util_set_source_color(surface, color);
|
2015-10-14 19:03:05 +02:00
|
|
|
|
|
|
|
cairo_paint(surface->cr);
|
|
|
|
|
|
|
|
/* Make sure we flush the surface for any text drawing operations that could follow.
|
|
|
|
* Since we support drawing text via XCB, we need this. */
|
|
|
|
CAIRO_SURFACE_FLUSH(surface->surface);
|
|
|
|
|
|
|
|
cairo_restore(surface->cr);
|
|
|
|
}
|
|
|
|
|
2015-10-08 12:31:56 +02:00
|
|
|
/**
|
|
|
|
* Copies a surface onto another surface.
|
|
|
|
*
|
|
|
|
*/
|
2017-01-13 18:34:09 +01:00
|
|
|
void draw_util_copy_surface(surface_t *src, surface_t *dest, double src_x, double src_y,
|
2015-10-14 20:49:52 +02:00
|
|
|
double dest_x, double dest_y, double width, double height) {
|
2015-11-16 21:28:33 +01:00
|
|
|
RETURN_UNLESS_SURFACE_INITIALIZED(src);
|
|
|
|
RETURN_UNLESS_SURFACE_INITIALIZED(dest);
|
|
|
|
|
2015-10-08 12:31:56 +02:00
|
|
|
cairo_save(dest->cr);
|
|
|
|
|
|
|
|
/* Using the SOURCE operator will copy both color and alpha information directly
|
|
|
|
* onto the surface rather than blending it. This is a bit more efficient and
|
|
|
|
* allows better color control for the user when using opacity. */
|
|
|
|
cairo_set_operator(dest->cr, CAIRO_OPERATOR_SOURCE);
|
2015-11-15 17:25:12 +01:00
|
|
|
cairo_set_source_surface(dest->cr, src->surface, dest_x - src_x, dest_y - src_y);
|
2015-10-08 12:31:56 +02:00
|
|
|
|
2015-10-14 20:49:52 +02:00
|
|
|
cairo_rectangle(dest->cr, dest_x, dest_y, width, height);
|
2015-10-08 12:31:56 +02:00
|
|
|
cairo_fill(dest->cr);
|
|
|
|
|
|
|
|
/* Make sure we flush the surface for any text drawing operations that could follow.
|
|
|
|
* Since we support drawing text via XCB, we need this. */
|
2015-10-14 18:57:16 +02:00
|
|
|
CAIRO_SURFACE_FLUSH(src->surface);
|
|
|
|
CAIRO_SURFACE_FLUSH(dest->surface);
|
2015-10-14 20:49:52 +02:00
|
|
|
|
2015-10-08 12:31:56 +02:00
|
|
|
cairo_restore(dest->cr);
|
|
|
|
}
|