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
This commit is contained in:
parent
d9bbfb7b35
commit
b665049883
|
@ -174,7 +174,7 @@ static void draw_separator(i3_output *output, uint32_t x, struct status_block *b
|
||||||
uint32_t center_x = x - sep_offset;
|
uint32_t center_x = x - sep_offset;
|
||||||
if (config.separator_symbol == NULL) {
|
if (config.separator_symbol == NULL) {
|
||||||
/* Draw a classic one pixel, vertical separator. */
|
/* Draw a classic one pixel, vertical separator. */
|
||||||
draw_util_rectangle(&output->statusline_buffer, sep_fg,
|
draw_util_rectangle(xcb_connection, &output->statusline_buffer, sep_fg,
|
||||||
center_x,
|
center_x,
|
||||||
logical_px(sep_voff_px),
|
logical_px(sep_voff_px),
|
||||||
logical_px(1),
|
logical_px(1),
|
||||||
|
@ -243,7 +243,7 @@ void draw_statusline(i3_output *output, uint32_t clip_left, bool use_focus_color
|
||||||
struct status_block *block;
|
struct status_block *block;
|
||||||
|
|
||||||
color_t bar_color = (use_focus_colors ? colors.focus_bar_bg : colors.bar_bg);
|
color_t bar_color = (use_focus_colors ? colors.focus_bar_bg : colors.bar_bg);
|
||||||
draw_util_clear_surface(&output->statusline_buffer, bar_color);
|
draw_util_clear_surface(xcb_connection, &output->statusline_buffer, bar_color);
|
||||||
|
|
||||||
/* Use unsigned integer wraparound to clip off the left side.
|
/* Use unsigned integer wraparound to clip off the left side.
|
||||||
* For example, if clip_left is 75, then x will start at the very large
|
* For example, if clip_left is 75, then x will start at the very large
|
||||||
|
@ -294,13 +294,13 @@ void draw_statusline(i3_output *output, uint32_t clip_left, bool use_focus_color
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Draw the border. */
|
/* Draw the border. */
|
||||||
draw_util_rectangle(&output->statusline_buffer, border_color,
|
draw_util_rectangle(xcb_connection, &output->statusline_buffer, border_color,
|
||||||
x, logical_px(1),
|
x, logical_px(1),
|
||||||
full_render_width,
|
full_render_width,
|
||||||
bar_height - logical_px(2));
|
bar_height - logical_px(2));
|
||||||
|
|
||||||
/* Draw the background. */
|
/* Draw the background. */
|
||||||
draw_util_rectangle(&output->statusline_buffer, bg_color,
|
draw_util_rectangle(xcb_connection, &output->statusline_buffer, bg_color,
|
||||||
x + border_width,
|
x + border_width,
|
||||||
logical_px(1) + border_width,
|
logical_px(1) + border_width,
|
||||||
full_render_width - 2 * border_width,
|
full_render_width - 2 * border_width,
|
||||||
|
@ -1709,9 +1709,9 @@ void reconfig_windows(bool redraw_bars) {
|
||||||
1,
|
1,
|
||||||
(unsigned char *)&atoms[_NET_WM_WINDOW_TYPE_DOCK]);
|
(unsigned char *)&atoms[_NET_WM_WINDOW_TYPE_DOCK]);
|
||||||
|
|
||||||
draw_util_surface_init(&walk->bar, bar_id, walk->rect.w, bar_height);
|
draw_util_surface_init(xcb_connection, &walk->bar, bar_id, NULL, walk->rect.w, bar_height);
|
||||||
draw_util_surface_init(&walk->buffer, buffer_id, walk->rect.w, bar_height);
|
draw_util_surface_init(xcb_connection, &walk->buffer, buffer_id, NULL, walk->rect.w, bar_height);
|
||||||
draw_util_surface_init(&walk->statusline_buffer, statusline_buffer_id, walk->rect.w, bar_height);
|
draw_util_surface_init(xcb_connection, &walk->statusline_buffer, statusline_buffer_id, NULL, walk->rect.w, bar_height);
|
||||||
|
|
||||||
xcb_void_cookie_t strut_cookie = config_strut_partial(walk);
|
xcb_void_cookie_t strut_cookie = config_strut_partial(walk);
|
||||||
|
|
||||||
|
@ -1820,12 +1820,12 @@ void reconfig_windows(bool redraw_bars) {
|
||||||
walk->rect.w,
|
walk->rect.w,
|
||||||
bar_height);
|
bar_height);
|
||||||
|
|
||||||
draw_util_surface_free(&(walk->bar));
|
draw_util_surface_free(xcb_connection, &(walk->bar));
|
||||||
draw_util_surface_free(&(walk->buffer));
|
draw_util_surface_free(xcb_connection, &(walk->buffer));
|
||||||
draw_util_surface_free(&(walk->statusline_buffer));
|
draw_util_surface_free(xcb_connection, &(walk->statusline_buffer));
|
||||||
draw_util_surface_init(&(walk->bar), walk->bar.id, walk->rect.w, bar_height);
|
draw_util_surface_init(xcb_connection, &(walk->bar), walk->bar.id, NULL, walk->rect.w, bar_height);
|
||||||
draw_util_surface_init(&(walk->buffer), walk->buffer.id, walk->rect.w, bar_height);
|
draw_util_surface_init(xcb_connection, &(walk->buffer), walk->buffer.id, NULL, walk->rect.w, bar_height);
|
||||||
draw_util_surface_init(&(walk->statusline_buffer), walk->statusline_buffer.id, walk->rect.w, bar_height);
|
draw_util_surface_init(xcb_connection, &(walk->statusline_buffer), walk->statusline_buffer.id, NULL, walk->rect.w, bar_height);
|
||||||
|
|
||||||
xcb_void_cookie_t map_cookie, umap_cookie;
|
xcb_void_cookie_t map_cookie, umap_cookie;
|
||||||
if (redraw_bars) {
|
if (redraw_bars) {
|
||||||
|
@ -1886,7 +1886,7 @@ void draw_bars(bool unhide) {
|
||||||
bool use_focus_colors = output_has_focus(outputs_walk);
|
bool use_focus_colors = output_has_focus(outputs_walk);
|
||||||
|
|
||||||
/* First things first: clear the backbuffer */
|
/* First things first: clear the backbuffer */
|
||||||
draw_util_clear_surface(&(outputs_walk->buffer),
|
draw_util_clear_surface(xcb_connection, &(outputs_walk->buffer),
|
||||||
(use_focus_colors ? colors.focus_bar_bg : colors.bar_bg));
|
(use_focus_colors ? colors.focus_bar_bg : colors.bar_bg));
|
||||||
|
|
||||||
if (!config.disable_ws) {
|
if (!config.disable_ws) {
|
||||||
|
@ -1917,14 +1917,14 @@ void draw_bars(bool unhide) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Draw the border of the button. */
|
/* Draw the border of the button. */
|
||||||
draw_util_rectangle(&(outputs_walk->buffer), border_color,
|
draw_util_rectangle(xcb_connection, &(outputs_walk->buffer), border_color,
|
||||||
workspace_width,
|
workspace_width,
|
||||||
logical_px(1),
|
logical_px(1),
|
||||||
ws_walk->name_width + 2 * logical_px(ws_hoff_px) + 2 * logical_px(1),
|
ws_walk->name_width + 2 * logical_px(ws_hoff_px) + 2 * logical_px(1),
|
||||||
font.height + 2 * logical_px(ws_voff_px) - 2 * logical_px(1));
|
font.height + 2 * logical_px(ws_voff_px) - 2 * logical_px(1));
|
||||||
|
|
||||||
/* Draw the inside of the button. */
|
/* Draw the inside of the button. */
|
||||||
draw_util_rectangle(&(outputs_walk->buffer), bg_color,
|
draw_util_rectangle(xcb_connection, &(outputs_walk->buffer), bg_color,
|
||||||
workspace_width + logical_px(1),
|
workspace_width + logical_px(1),
|
||||||
2 * logical_px(1),
|
2 * logical_px(1),
|
||||||
ws_walk->name_width + 2 * logical_px(ws_hoff_px),
|
ws_walk->name_width + 2 * logical_px(ws_hoff_px),
|
||||||
|
@ -1947,13 +1947,13 @@ void draw_bars(bool unhide) {
|
||||||
color_t fg_color = colors.binding_mode_fg;
|
color_t fg_color = colors.binding_mode_fg;
|
||||||
color_t bg_color = colors.binding_mode_bg;
|
color_t bg_color = colors.binding_mode_bg;
|
||||||
|
|
||||||
draw_util_rectangle(&(outputs_walk->buffer), colors.binding_mode_border,
|
draw_util_rectangle(xcb_connection, &(outputs_walk->buffer), colors.binding_mode_border,
|
||||||
workspace_width,
|
workspace_width,
|
||||||
logical_px(1),
|
logical_px(1),
|
||||||
binding.width + 2 * logical_px(ws_hoff_px) + 2 * logical_px(1),
|
binding.width + 2 * logical_px(ws_hoff_px) + 2 * logical_px(1),
|
||||||
font.height + 2 * logical_px(ws_voff_px) - 2 * logical_px(1));
|
font.height + 2 * logical_px(ws_voff_px) - 2 * logical_px(1));
|
||||||
|
|
||||||
draw_util_rectangle(&(outputs_walk->buffer), bg_color,
|
draw_util_rectangle(xcb_connection, &(outputs_walk->buffer), bg_color,
|
||||||
workspace_width + logical_px(1),
|
workspace_width + logical_px(1),
|
||||||
2 * logical_px(1),
|
2 * logical_px(1),
|
||||||
binding.width + 2 * logical_px(ws_hoff_px),
|
binding.width + 2 * logical_px(ws_hoff_px),
|
||||||
|
@ -1989,7 +1989,7 @@ void draw_bars(bool unhide) {
|
||||||
int x_dest = outputs_walk->rect.w - tray_width - logical_px(sb_hoff_px) - visible_statusline_width;
|
int x_dest = outputs_walk->rect.w - tray_width - logical_px(sb_hoff_px) - visible_statusline_width;
|
||||||
|
|
||||||
draw_statusline(outputs_walk, clip_left, use_focus_colors, use_short_text);
|
draw_statusline(outputs_walk, clip_left, use_focus_colors, use_short_text);
|
||||||
draw_util_copy_surface(&outputs_walk->statusline_buffer, &outputs_walk->buffer, 0, 0,
|
draw_util_copy_surface(xcb_connection, &outputs_walk->statusline_buffer, &outputs_walk->buffer, 0, 0,
|
||||||
x_dest, 0, visible_statusline_width, (int16_t)bar_height);
|
x_dest, 0, visible_statusline_width, (int16_t)bar_height);
|
||||||
|
|
||||||
outputs_walk->statusline_width = statusline_width;
|
outputs_walk->statusline_width = statusline_width;
|
||||||
|
@ -2020,7 +2020,7 @@ void redraw_bars(void) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
draw_util_copy_surface(&(outputs_walk->buffer), &(outputs_walk->bar), 0, 0,
|
draw_util_copy_surface(xcb_connection, &(outputs_walk->buffer), &(outputs_walk->bar), 0, 0,
|
||||||
0, 0, outputs_walk->rect.w, outputs_walk->rect.h);
|
0, 0, outputs_walk->rect.w, outputs_walk->rect.h);
|
||||||
xcb_flush(xcb_connection);
|
xcb_flush(xcb_connection);
|
||||||
}
|
}
|
||||||
|
|
|
@ -551,11 +551,10 @@ struct Con {
|
||||||
* change. */
|
* change. */
|
||||||
uint8_t ignore_unmap;
|
uint8_t ignore_unmap;
|
||||||
|
|
||||||
/* ids/pixmap/graphics context for the frame window */
|
/* The surface used for the frame window. */
|
||||||
|
surface_t frame;
|
||||||
|
surface_t frame_buffer;
|
||||||
bool pixmap_recreated;
|
bool pixmap_recreated;
|
||||||
xcb_window_t frame;
|
|
||||||
xcb_pixmap_t pixmap;
|
|
||||||
xcb_gcontext_t pm_gc;
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
CT_ROOT = 0,
|
CT_ROOT = 0,
|
||||||
|
|
|
@ -513,6 +513,8 @@ typedef struct surface_t {
|
||||||
/* A classic XCB graphics context. */
|
/* A classic XCB graphics context. */
|
||||||
xcb_gcontext_t gc;
|
xcb_gcontext_t gc;
|
||||||
|
|
||||||
|
xcb_visualtype_t *visual_type;
|
||||||
|
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
|
|
||||||
|
@ -530,13 +532,20 @@ typedef struct surface_t {
|
||||||
* Initialize the surface to represent the given drawable.
|
* Initialize the surface to represent the given drawable.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void draw_util_surface_init(surface_t *surface, xcb_drawable_t drawable, int width, int height);
|
void draw_util_surface_init(xcb_connection_t *conn, surface_t *surface, xcb_drawable_t drawable,
|
||||||
|
xcb_visualtype_t *visual, int width, int height);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resize the surface to the given size.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void draw_util_surface_set_size(surface_t *surface, int width, int height);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroys the surface.
|
* Destroys the surface.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void draw_util_surface_free(surface_t *surface);
|
void draw_util_surface_free(xcb_connection_t *conn, surface_t *surface);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the given color in hex format to an internal color representation.
|
* Parses the given color in hex format to an internal color representation.
|
||||||
|
@ -545,6 +554,8 @@ void draw_util_surface_free(surface_t *surface);
|
||||||
*/
|
*/
|
||||||
color_t draw_util_hex_to_color(const char *color);
|
color_t draw_util_hex_to_color(const char *color);
|
||||||
|
|
||||||
|
color_t draw_util_colorpixel_to_color(uint32_t colorpixel);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draw the given text using libi3.
|
* Draw the given text using libi3.
|
||||||
* This function also marks the surface dirty which is needed if other means of
|
* This function also marks the surface dirty which is needed if other means of
|
||||||
|
@ -559,17 +570,17 @@ void draw_util_text(i3String *text, surface_t *surface, color_t fg_color, color_
|
||||||
* surface as well as restoring the cairo state.
|
* surface as well as restoring the cairo state.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void draw_util_rectangle(surface_t *surface, color_t color, double x, double y, double w, double h);
|
void draw_util_rectangle(xcb_connection_t *conn, surface_t *surface, color_t color, double x, double y, double w, double h);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears a surface with the given color.
|
* Clears a surface with the given color.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void draw_util_clear_surface(surface_t *surface, color_t color);
|
void draw_util_clear_surface(xcb_connection_t *conn, surface_t *surface, color_t color);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copies a surface onto another surface.
|
* Copies a surface onto another surface.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void draw_util_copy_surface(surface_t *src, surface_t *dest, double src_x, double src_y,
|
void draw_util_copy_surface(xcb_connection_t *conn, surface_t *src, surface_t *dest, double src_x, double src_y,
|
||||||
double dest_x, double dest_y, double width, double height);
|
double dest_x, double dest_y, double width, double height);
|
||||||
|
|
|
@ -139,6 +139,7 @@ void xcb_set_root_cursor(int cursor);
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
uint16_t get_visual_depth(xcb_visualid_t visual_id);
|
uint16_t get_visual_depth(xcb_visualid_t visual_id);
|
||||||
|
xcb_visualtype_t *get_visualtype_by_id(xcb_visualid_t visual_id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get visualid with specified depth
|
* Get visualid with specified depth
|
||||||
|
|
|
@ -17,32 +17,34 @@
|
||||||
|
|
||||||
#include "libi3.h"
|
#include "libi3.h"
|
||||||
|
|
||||||
xcb_connection_t *xcb_connection;
|
/* The default visual_type to use if none is specified when creating the surface. Must be defined globally. */
|
||||||
xcb_visualtype_t *visual_type;
|
xcb_visualtype_t *visual_type;
|
||||||
|
|
||||||
/* Forward declarations */
|
/* Forward declarations */
|
||||||
static void draw_util_set_source_color(surface_t *surface, color_t color);
|
static void draw_util_set_source_color(xcb_connection_t *conn, surface_t *surface, color_t color);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the surface to represent the given drawable.
|
* Initialize the surface to represent the given drawable.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void draw_util_surface_init(surface_t *surface, xcb_drawable_t drawable, int width, int height) {
|
void draw_util_surface_init(xcb_connection_t *conn, surface_t *surface, xcb_drawable_t drawable,
|
||||||
|
xcb_visualtype_t *visual, int width, int height) {
|
||||||
surface->id = drawable;
|
surface->id = drawable;
|
||||||
|
surface->visual_type = (visual == NULL) ? visual_type : visual;
|
||||||
surface->width = width;
|
surface->width = width;
|
||||||
surface->height = height;
|
surface->height = height;
|
||||||
|
|
||||||
surface->gc = xcb_generate_id(xcb_connection);
|
surface->gc = xcb_generate_id(conn);
|
||||||
xcb_void_cookie_t gc_cookie = xcb_create_gc_checked(xcb_connection, surface->gc, surface->id, 0, NULL);
|
xcb_void_cookie_t gc_cookie = xcb_create_gc_checked(conn, surface->gc, surface->id, 0, NULL);
|
||||||
|
|
||||||
xcb_generic_error_t *error = xcb_request_check(xcb_connection, gc_cookie);
|
xcb_generic_error_t *error = xcb_request_check(conn, gc_cookie);
|
||||||
if (error != NULL) {
|
if (error != NULL) {
|
||||||
ELOG("Could not create graphical context. Error code: %d\n", error->error_code);
|
ELOG("Could not create graphical context. Error code: %d\n", error->error_code);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CAIRO_SUPPORT
|
#ifdef CAIRO_SUPPORT
|
||||||
surface->surface = cairo_xcb_surface_create(xcb_connection, surface->id, visual_type, width, height);
|
surface->surface = cairo_xcb_surface_create(conn, surface->id, surface->visual_type, width, height);
|
||||||
surface->cr = cairo_create(surface->surface);
|
surface->cr = cairo_create(surface->surface);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -51,14 +53,26 @@ void draw_util_surface_init(surface_t *surface, xcb_drawable_t drawable, int wid
|
||||||
* Destroys the surface.
|
* Destroys the surface.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void draw_util_surface_free(surface_t *surface) {
|
void draw_util_surface_free(xcb_connection_t *conn, surface_t *surface) {
|
||||||
xcb_free_gc(xcb_connection, surface->gc);
|
xcb_free_gc(conn, surface->gc);
|
||||||
#ifdef CAIRO_SUPPORT
|
#ifdef CAIRO_SUPPORT
|
||||||
cairo_surface_destroy(surface->surface);
|
cairo_surface_destroy(surface->surface);
|
||||||
cairo_destroy(surface->cr);
|
cairo_destroy(surface->cr);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
#ifdef CAIRO_SUPPORT
|
||||||
|
cairo_xcb_surface_set_size(surface->surface, width, height);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parses the given color in hex format to an internal color representation.
|
* 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".
|
* Note that the input must begin with a hash sign, e.g., "#3fbc59".
|
||||||
|
@ -77,16 +91,24 @@ color_t draw_util_hex_to_color(const char *color) {
|
||||||
.colorpixel = get_colorpixel(color)};
|
.colorpixel = get_colorpixel(color)};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
color_t draw_util_colorpixel_to_color(uint32_t colorpixel) {
|
||||||
|
return (color_t){
|
||||||
|
.red = ((colorpixel >> 16) & 0xFF) / 255.0,
|
||||||
|
.green = ((colorpixel >> 8) & 0xFF) / 255.0,
|
||||||
|
.blue = (colorpixel & 0xFF) / 255.0,
|
||||||
|
.colorpixel = colorpixel};
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set the given color as the source color on the surface.
|
* Set the given color as the source color on the surface.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static void draw_util_set_source_color(surface_t *surface, color_t color) {
|
static void draw_util_set_source_color(xcb_connection_t *conn, surface_t *surface, color_t color) {
|
||||||
#ifdef CAIRO_SUPPORT
|
#ifdef CAIRO_SUPPORT
|
||||||
cairo_set_source_rgb(surface->cr, color.red, color.green, color.blue);
|
cairo_set_source_rgb(surface->cr, color.red, color.green, color.blue);
|
||||||
#else
|
#else
|
||||||
uint32_t colorpixel = color.colorpixel;
|
uint32_t colorpixel = color.colorpixel;
|
||||||
xcb_change_gc(xcb_connection, surface->gc, XCB_GC_FOREGROUND | XCB_GC_BACKGROUND,
|
xcb_change_gc(conn, surface->gc, XCB_GC_FOREGROUND | XCB_GC_BACKGROUND,
|
||||||
(uint32_t[]){colorpixel, colorpixel});
|
(uint32_t[]){colorpixel, colorpixel});
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -104,7 +126,7 @@ void draw_util_text(i3String *text, surface_t *surface, color_t fg_color, color_
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
set_font_colors(surface->gc, fg_color.colorpixel, bg_color.colorpixel);
|
set_font_colors(surface->gc, fg_color.colorpixel, bg_color.colorpixel);
|
||||||
draw_text(text, surface->id, surface->gc, visual_type, x, y, max_width);
|
draw_text(text, surface->id, surface->gc, surface->visual_type, x, y, max_width);
|
||||||
|
|
||||||
#ifdef CAIRO_SUPPORT
|
#ifdef CAIRO_SUPPORT
|
||||||
/* Notify cairo that we (possibly) used another way to draw on the surface. */
|
/* Notify cairo that we (possibly) used another way to draw on the surface. */
|
||||||
|
@ -118,7 +140,7 @@ void draw_util_text(i3String *text, surface_t *surface, color_t fg_color, color_
|
||||||
* surface as well as restoring the cairo state.
|
* surface as well as restoring the cairo state.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void draw_util_rectangle(surface_t *surface, color_t color, double x, double y, double w, double h) {
|
void draw_util_rectangle(xcb_connection_t *conn, surface_t *surface, color_t color, double x, double y, double w, double h) {
|
||||||
#ifdef CAIRO_SUPPORT
|
#ifdef CAIRO_SUPPORT
|
||||||
cairo_save(surface->cr);
|
cairo_save(surface->cr);
|
||||||
|
|
||||||
|
@ -126,7 +148,7 @@ void draw_util_rectangle(surface_t *surface, color_t color, double x, double y,
|
||||||
* onto the surface rather than blending it. This is a bit more efficient and
|
* onto the surface rather than blending it. This is a bit more efficient and
|
||||||
* allows better color control for the user when using opacity. */
|
* allows better color control for the user when using opacity. */
|
||||||
cairo_set_operator(surface->cr, CAIRO_OPERATOR_SOURCE);
|
cairo_set_operator(surface->cr, CAIRO_OPERATOR_SOURCE);
|
||||||
draw_util_set_source_color(surface, color);
|
draw_util_set_source_color(conn, surface, color);
|
||||||
|
|
||||||
cairo_rectangle(surface->cr, x, y, w, h);
|
cairo_rectangle(surface->cr, x, y, w, h);
|
||||||
cairo_fill(surface->cr);
|
cairo_fill(surface->cr);
|
||||||
|
@ -137,10 +159,10 @@ void draw_util_rectangle(surface_t *surface, color_t color, double x, double y,
|
||||||
|
|
||||||
cairo_restore(surface->cr);
|
cairo_restore(surface->cr);
|
||||||
#else
|
#else
|
||||||
draw_util_set_source_color(surface, color);
|
draw_util_set_source_color(conn, surface, color);
|
||||||
|
|
||||||
xcb_rectangle_t rect = {x, y, w, h};
|
xcb_rectangle_t rect = {x, y, w, h};
|
||||||
xcb_poly_fill_rectangle(xcb_connection, surface->id, surface->gc, 1, &rect);
|
xcb_poly_fill_rectangle(conn, surface->id, surface->gc, 1, &rect);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +170,7 @@ void draw_util_rectangle(surface_t *surface, color_t color, double x, double y,
|
||||||
* Clears a surface with the given color.
|
* Clears a surface with the given color.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void draw_util_clear_surface(surface_t *surface, color_t color) {
|
void draw_util_clear_surface(xcb_connection_t *conn, surface_t *surface, color_t color) {
|
||||||
#ifdef CAIRO_SUPPORT
|
#ifdef CAIRO_SUPPORT
|
||||||
cairo_save(surface->cr);
|
cairo_save(surface->cr);
|
||||||
|
|
||||||
|
@ -156,7 +178,7 @@ void draw_util_clear_surface(surface_t *surface, color_t color) {
|
||||||
* onto the surface rather than blending it. This is a bit more efficient and
|
* onto the surface rather than blending it. This is a bit more efficient and
|
||||||
* allows better color control for the user when using opacity. */
|
* allows better color control for the user when using opacity. */
|
||||||
cairo_set_operator(surface->cr, CAIRO_OPERATOR_SOURCE);
|
cairo_set_operator(surface->cr, CAIRO_OPERATOR_SOURCE);
|
||||||
draw_util_set_source_color(surface, color);
|
draw_util_set_source_color(conn, surface, color);
|
||||||
|
|
||||||
cairo_paint(surface->cr);
|
cairo_paint(surface->cr);
|
||||||
|
|
||||||
|
@ -166,10 +188,10 @@ void draw_util_clear_surface(surface_t *surface, color_t color) {
|
||||||
|
|
||||||
cairo_restore(surface->cr);
|
cairo_restore(surface->cr);
|
||||||
#else
|
#else
|
||||||
draw_util_set_source_color(surface, color);
|
draw_util_set_source_color(conn, surface, color);
|
||||||
|
|
||||||
xcb_rectangle_t rect = {0, 0, surface->width, surface->height};
|
xcb_rectangle_t rect = {0, 0, surface->width, surface->height};
|
||||||
xcb_poly_fill_rectangle(xcb_connection, surface->id, surface->gc, 1, &rect);
|
xcb_poly_fill_rectangle(conn, surface->id, surface->gc, 1, &rect);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,7 +199,7 @@ void draw_util_clear_surface(surface_t *surface, color_t color) {
|
||||||
* Copies a surface onto another surface.
|
* Copies a surface onto another surface.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void draw_util_copy_surface(surface_t *src, surface_t *dest, double src_x, double src_y,
|
void draw_util_copy_surface(xcb_connection_t *conn, surface_t *src, surface_t *dest, double src_x, double src_y,
|
||||||
double dest_x, double dest_y, double width, double height) {
|
double dest_x, double dest_y, double width, double height) {
|
||||||
#ifdef CAIRO_SUPPORT
|
#ifdef CAIRO_SUPPORT
|
||||||
cairo_save(dest->cr);
|
cairo_save(dest->cr);
|
||||||
|
@ -198,7 +220,7 @@ void draw_util_copy_surface(surface_t *src, surface_t *dest, double src_x, doubl
|
||||||
|
|
||||||
cairo_restore(dest->cr);
|
cairo_restore(dest->cr);
|
||||||
#else
|
#else
|
||||||
xcb_copy_area(xcb_connection, src->id, dest->id, dest->gc, (int16_t)src_x, (int16_t)src_y,
|
xcb_copy_area(conn, src->id, dest->id, dest->gc, (int16_t)src_x, (int16_t)src_y,
|
||||||
(int16_t)dest_x, (int16_t)dest_y, (uint16_t)width, (uint16_t)height);
|
(int16_t)dest_x, (int16_t)dest_y, (uint16_t)width, (uint16_t)height);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -514,7 +514,7 @@ Con *con_by_window_id(xcb_window_t window) {
|
||||||
Con *con_by_frame_id(xcb_window_t frame) {
|
Con *con_by_frame_id(xcb_window_t frame) {
|
||||||
Con *con;
|
Con *con;
|
||||||
TAILQ_FOREACH(con, &all_cons, all_cons)
|
TAILQ_FOREACH(con, &all_cons, all_cons)
|
||||||
if (con->frame == frame)
|
if (con->frame.id == frame)
|
||||||
return con;
|
return con;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -656,15 +656,14 @@ static void handle_expose_event(xcb_expose_event_t *event) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Since we render to our pixmap on every change anyways, expose events
|
/* Since we render to our surface on every change anyways, expose events
|
||||||
* only tell us that the X server lost (parts of) the window contents. We
|
* only tell us that the X server lost (parts of) the window contents. We
|
||||||
* can handle that by copying the appropriate part from our pixmap to the
|
* can handle that by copying the appropriate part from our surface to the
|
||||||
* window. */
|
* window. */
|
||||||
xcb_copy_area(conn, parent->pixmap, parent->frame, parent->pm_gc,
|
draw_util_copy_surface(conn, &(parent->frame_buffer), &(parent->frame),
|
||||||
event->x, event->y, event->x, event->y,
|
event->x, event->y, event->x, event->y,
|
||||||
event->width, event->height);
|
event->width, event->height);
|
||||||
xcb_flush(conn);
|
xcb_flush(conn);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,7 @@ xcb_window_t root;
|
||||||
* otherwise the root window’s default (usually 24 bit TrueColor). */
|
* otherwise the root window’s default (usually 24 bit TrueColor). */
|
||||||
uint8_t root_depth;
|
uint8_t root_depth;
|
||||||
xcb_visualid_t visual_id;
|
xcb_visualid_t visual_id;
|
||||||
|
xcb_visualtype_t *visual_type;
|
||||||
xcb_colormap_t colormap;
|
xcb_colormap_t colormap;
|
||||||
|
|
||||||
struct ev_loop *main_loop;
|
struct ev_loop *main_loop;
|
||||||
|
@ -487,6 +488,7 @@ int main(int argc, char *argv[]) {
|
||||||
* transparency) and use it if so. */
|
* transparency) and use it if so. */
|
||||||
root_depth = root_screen->root_depth;
|
root_depth = root_screen->root_depth;
|
||||||
visual_id = root_screen->root_visual;
|
visual_id = root_screen->root_visual;
|
||||||
|
visual_type = get_visualtype(root_screen);
|
||||||
colormap = root_screen->default_colormap;
|
colormap = root_screen->default_colormap;
|
||||||
|
|
||||||
DLOG("root_depth = %d, visual_id = 0x%08x.\n", root_depth, visual_id);
|
DLOG("root_depth = %d, visual_id = 0x%08x.\n", root_depth, visual_id);
|
||||||
|
|
|
@ -473,7 +473,7 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki
|
||||||
values[0] = XCB_NONE;
|
values[0] = XCB_NONE;
|
||||||
xcb_change_window_attributes(conn, window, XCB_CW_EVENT_MASK, values);
|
xcb_change_window_attributes(conn, window, XCB_CW_EVENT_MASK, values);
|
||||||
|
|
||||||
xcb_void_cookie_t rcookie = xcb_reparent_window_checked(conn, window, nc->frame, 0, 0);
|
xcb_void_cookie_t rcookie = xcb_reparent_window_checked(conn, window, nc->frame.id, 0, 0);
|
||||||
if (xcb_request_check(conn, rcookie) != NULL) {
|
if (xcb_request_check(conn, rcookie) != NULL) {
|
||||||
LOG("Could not reparent the window, aborting\n");
|
LOG("Could not reparent the window, aborting\n");
|
||||||
goto geom_out;
|
goto geom_out;
|
||||||
|
|
293
src/x.c
293
src/x.c
|
@ -144,10 +144,11 @@ void x_con_init(Con *con, uint16_t depth) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Rect dims = {-15, -15, 10, 10};
|
Rect dims = {-15, -15, 10, 10};
|
||||||
con->frame = create_window(conn, dims, depth, visual, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCURSOR_CURSOR_POINTER, false, mask, values);
|
xcb_window_t frame_id = create_window(conn, dims, depth, visual, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCURSOR_CURSOR_POINTER, false, mask, values);
|
||||||
|
draw_util_surface_init(conn, &(con->frame), frame_id, get_visualtype_by_id(visual), dims.width, dims.height);
|
||||||
xcb_change_property(conn,
|
xcb_change_property(conn,
|
||||||
XCB_PROP_MODE_REPLACE,
|
XCB_PROP_MODE_REPLACE,
|
||||||
con->frame,
|
con->frame.id,
|
||||||
XCB_ATOM_WM_CLASS,
|
XCB_ATOM_WM_CLASS,
|
||||||
XCB_ATOM_STRING,
|
XCB_ATOM_STRING,
|
||||||
8,
|
8,
|
||||||
|
@ -158,7 +159,7 @@ void x_con_init(Con *con, uint16_t depth) {
|
||||||
xcb_free_colormap(conn, win_colormap);
|
xcb_free_colormap(conn, win_colormap);
|
||||||
|
|
||||||
struct con_state *state = scalloc(1, sizeof(struct con_state));
|
struct con_state *state = scalloc(1, sizeof(struct con_state));
|
||||||
state->id = con->frame;
|
state->id = con->frame.id;
|
||||||
state->mapped = false;
|
state->mapped = false;
|
||||||
state->initial = true;
|
state->initial = true;
|
||||||
DLOG("Adding window 0x%08x to lists\n", state->id);
|
DLOG("Adding window 0x%08x to lists\n", state->id);
|
||||||
|
@ -177,7 +178,7 @@ void x_con_init(Con *con, uint16_t depth) {
|
||||||
void x_reinit(Con *con) {
|
void x_reinit(Con *con) {
|
||||||
struct con_state *state;
|
struct con_state *state;
|
||||||
|
|
||||||
if ((state = state_for_frame(con->frame)) == NULL) {
|
if ((state = state_for_frame(con->frame.id)) == NULL) {
|
||||||
ELOG("window state not found\n");
|
ELOG("window state not found\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -196,13 +197,13 @@ void x_reinit(Con *con) {
|
||||||
*/
|
*/
|
||||||
void x_reparent_child(Con *con, Con *old) {
|
void x_reparent_child(Con *con, Con *old) {
|
||||||
struct con_state *state;
|
struct con_state *state;
|
||||||
if ((state = state_for_frame(con->frame)) == NULL) {
|
if ((state = state_for_frame(con->frame.id)) == NULL) {
|
||||||
ELOG("window state for con not found\n");
|
ELOG("window state for con not found\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
state->need_reparent = true;
|
state->need_reparent = true;
|
||||||
state->old_frame = old->frame;
|
state->old_frame = old->frame.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -212,12 +213,12 @@ void x_reparent_child(Con *con, Con *old) {
|
||||||
void x_move_win(Con *src, Con *dest) {
|
void x_move_win(Con *src, Con *dest) {
|
||||||
struct con_state *state_src, *state_dest;
|
struct con_state *state_src, *state_dest;
|
||||||
|
|
||||||
if ((state_src = state_for_frame(src->frame)) == NULL) {
|
if ((state_src = state_for_frame(src->frame.id)) == NULL) {
|
||||||
ELOG("window state for src not found\n");
|
ELOG("window state for src not found\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((state_dest = state_for_frame(dest->frame)) == NULL) {
|
if ((state_dest = state_for_frame(dest->frame.id)) == NULL) {
|
||||||
ELOG("window state for dest not found\n");
|
ELOG("window state for dest not found\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -239,10 +240,11 @@ void x_move_win(Con *src, Con *dest) {
|
||||||
void x_con_kill(Con *con) {
|
void x_con_kill(Con *con) {
|
||||||
con_state *state;
|
con_state *state;
|
||||||
|
|
||||||
xcb_destroy_window(conn, con->frame);
|
draw_util_surface_free(conn, &(con->frame));
|
||||||
xcb_free_pixmap(conn, con->pixmap);
|
draw_util_surface_free(conn, &(con->frame_buffer));
|
||||||
xcb_free_gc(conn, con->pm_gc);
|
xcb_destroy_window(conn, con->frame.id);
|
||||||
state = state_for_frame(con->frame);
|
xcb_free_pixmap(conn, con->frame_buffer.id);
|
||||||
|
state = state_for_frame(con->frame.id);
|
||||||
CIRCLEQ_REMOVE(&state_head, state, state);
|
CIRCLEQ_REMOVE(&state_head, state, state);
|
||||||
CIRCLEQ_REMOVE(&old_state_head, state, old_state);
|
CIRCLEQ_REMOVE(&old_state_head, state, old_state);
|
||||||
TAILQ_REMOVE(&initial_mapping_head, state, initial_mapping_order);
|
TAILQ_REMOVE(&initial_mapping_head, state, initial_mapping_order);
|
||||||
|
@ -312,6 +314,54 @@ void x_window_kill(xcb_window_t window, kill_window_t kill_window) {
|
||||||
free(event);
|
free(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void x_draw_decoration_border(Con *con, struct deco_render_params *p) {
|
||||||
|
assert(con->parent != NULL);
|
||||||
|
|
||||||
|
Rect *dr = &(con->deco_rect);
|
||||||
|
adjacent_t borders_to_hide = con_adjacent_borders(con) & config.hide_edge_borders;
|
||||||
|
int deco_diff_l = borders_to_hide & ADJ_LEFT_SCREEN_EDGE ? 0 : con->current_border_width;
|
||||||
|
int deco_diff_r = borders_to_hide & ADJ_RIGHT_SCREEN_EDGE ? 0 : con->current_border_width;
|
||||||
|
if (con->parent->layout == L_TABBED ||
|
||||||
|
(con->parent->layout == L_STACKED && TAILQ_NEXT(con, nodes) != NULL)) {
|
||||||
|
deco_diff_l = 0;
|
||||||
|
deco_diff_r = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
draw_util_rectangle(conn, &(con->parent->frame_buffer), draw_util_colorpixel_to_color(p->color->border),
|
||||||
|
dr->x, dr->y, dr->width, 1);
|
||||||
|
|
||||||
|
draw_util_rectangle(conn, &(con->parent->frame_buffer), draw_util_colorpixel_to_color(p->color->border),
|
||||||
|
dr->x + deco_diff_l, dr->y + dr->height - 1, dr->width - (deco_diff_l + deco_diff_r), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void x_draw_decoration_after_title(Con *con, struct deco_render_params *p) {
|
||||||
|
assert(con->parent != NULL);
|
||||||
|
|
||||||
|
Rect *dr = &(con->deco_rect);
|
||||||
|
Rect br = con_border_style_rect(con);
|
||||||
|
|
||||||
|
/* Redraw the right border to cut off any text that went past it.
|
||||||
|
* This is necessary when the text was drawn using XCB since cutting text off
|
||||||
|
* automatically does not work there. For pango rendering, this isn't necessary. */
|
||||||
|
draw_util_rectangle(conn, &(con->parent->frame_buffer), draw_util_colorpixel_to_color(p->color->background),
|
||||||
|
dr->x + dr->width + br.width, dr->y, -br.width, dr->height);
|
||||||
|
|
||||||
|
/* Draw a 1px separator line before and after every tab, so that tabs can
|
||||||
|
* be easily distinguished. */
|
||||||
|
if (con->parent->layout == L_TABBED) {
|
||||||
|
/* Left side */
|
||||||
|
draw_util_rectangle(conn, &(con->parent->frame_buffer), draw_util_colorpixel_to_color(p->color->border),
|
||||||
|
dr->x, dr->y, 1, dr->height);
|
||||||
|
|
||||||
|
/* Right side */
|
||||||
|
draw_util_rectangle(conn, &(con->parent->frame_buffer), draw_util_colorpixel_to_color(p->color->border),
|
||||||
|
dr->x + dr->width - 1, dr->y, 1, dr->height);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Redraw the border. */
|
||||||
|
x_draw_decoration_border(con, p);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Draws the decoration of the given container onto its parent.
|
* Draws the decoration of the given container onto its parent.
|
||||||
*
|
*
|
||||||
|
@ -343,7 +393,7 @@ void x_draw_decoration(Con *con) {
|
||||||
/* Skip containers whose pixmap has not yet been created (can happen when
|
/* Skip containers whose pixmap has not yet been created (can happen when
|
||||||
* decoration rendering happens recursively for a window for which
|
* decoration rendering happens recursively for a window for which
|
||||||
* x_push_node() was not yet called) */
|
* x_push_node() was not yet called) */
|
||||||
if (leaf && con->pixmap == XCB_NONE)
|
if (leaf && con->frame_buffer.id == XCB_NONE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* 1: build deco_params and compare with cache */
|
/* 1: build deco_params and compare with cache */
|
||||||
|
@ -395,29 +445,20 @@ void x_draw_decoration(Con *con) {
|
||||||
con->pixmap_recreated = false;
|
con->pixmap_recreated = false;
|
||||||
con->mark_changed = false;
|
con->mark_changed = false;
|
||||||
|
|
||||||
/* 2: draw the client.background, but only for the parts around the client_rect */
|
/* 2: draw the client.background, but only for the parts around the window_rect */
|
||||||
if (con->window != NULL) {
|
if (con->window != NULL) {
|
||||||
xcb_rectangle_t background[] = {
|
|
||||||
/* top area */
|
/* top area */
|
||||||
{0, 0, r->width, w->y},
|
draw_util_rectangle(conn, &(con->frame_buffer), draw_util_colorpixel_to_color(config.client.background),
|
||||||
|
0, 0, r->width, w->y);
|
||||||
/* bottom area */
|
/* bottom area */
|
||||||
{0, (w->y + w->height), r->width, r->height - (w->y + w->height)},
|
draw_util_rectangle(conn, &(con->frame_buffer), draw_util_colorpixel_to_color(config.client.background),
|
||||||
|
0, w->y + w->height, r->width, r->height - (w->y + w->height));
|
||||||
/* left area */
|
/* left area */
|
||||||
{0, 0, w->x, r->height},
|
draw_util_rectangle(conn, &(con->frame_buffer), draw_util_colorpixel_to_color(config.client.background),
|
||||||
|
0, 0, w->x, r->height);
|
||||||
/* right area */
|
/* right area */
|
||||||
{w->x + w->width, 0, r->width - (w->x + w->width), r->height}};
|
draw_util_rectangle(conn, &(con->frame_buffer), draw_util_colorpixel_to_color(config.client.background),
|
||||||
#if 0
|
w->x + w->width, 0, r->width - (w->x + w->width), r->height);
|
||||||
for (int i = 0; i < 4; i++)
|
|
||||||
DLOG("rect is (%d, %d) with %d x %d\n",
|
|
||||||
background[i].x,
|
|
||||||
background[i].y,
|
|
||||||
background[i].width,
|
|
||||||
background[i].height
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
xcb_change_gc(conn, con->pm_gc, XCB_GC_FOREGROUND, (uint32_t[]){config.client.background});
|
|
||||||
xcb_poly_fill_rectangle(conn, con->pixmap, con->pm_gc, sizeof(background) / sizeof(xcb_rectangle_t), background);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 3: draw a rectangle in border color around the client */
|
/* 3: draw a rectangle in border color around the client */
|
||||||
|
@ -433,27 +474,26 @@ void x_draw_decoration(Con *con) {
|
||||||
DLOG("window_rect spans (%d, %d) with %d x %d\n", con->window_rect.x, con->window_rect.y, con->window_rect.width, con->window_rect.height);
|
DLOG("window_rect spans (%d, %d) with %d x %d\n", con->window_rect.x, con->window_rect.y, con->window_rect.width, con->window_rect.height);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* These rectangles represents the border around the child window
|
/* These rectangles represent the border around the child window
|
||||||
* (left, bottom and right part). We don’t just fill the whole
|
* (left, bottom and right part). We don’t just fill the whole
|
||||||
* rectangle because some childs are not freely resizable and we want
|
* rectangle because some childs are not freely resizable and we want
|
||||||
* their background color to "shine through". */
|
* their background color to "shine through". */
|
||||||
xcb_change_gc(conn, con->pm_gc, XCB_GC_FOREGROUND, (uint32_t[]){p->color->background});
|
|
||||||
if (!(borders_to_hide & ADJ_LEFT_SCREEN_EDGE)) {
|
if (!(borders_to_hide & ADJ_LEFT_SCREEN_EDGE)) {
|
||||||
xcb_rectangle_t leftline = {0, 0, br.x, r->height};
|
draw_util_rectangle(conn, &(con->frame_buffer), draw_util_colorpixel_to_color(p->color->background),
|
||||||
xcb_poly_fill_rectangle(conn, con->pixmap, con->pm_gc, 1, &leftline);
|
0, 0, br.x, r->height);
|
||||||
}
|
}
|
||||||
if (!(borders_to_hide & ADJ_RIGHT_SCREEN_EDGE)) {
|
if (!(borders_to_hide & ADJ_RIGHT_SCREEN_EDGE)) {
|
||||||
xcb_rectangle_t rightline = {r->width + (br.width + br.x), 0, -(br.width + br.x), r->height};
|
draw_util_rectangle(conn, &(con->frame_buffer), draw_util_colorpixel_to_color(p->color->background),
|
||||||
xcb_poly_fill_rectangle(conn, con->pixmap, con->pm_gc, 1, &rightline);
|
r->width + (br.width + br.x), 0, -(br.width + br.x), r->height);
|
||||||
}
|
}
|
||||||
if (!(borders_to_hide & ADJ_LOWER_SCREEN_EDGE)) {
|
if (!(borders_to_hide & ADJ_LOWER_SCREEN_EDGE)) {
|
||||||
xcb_rectangle_t bottomline = {br.x, r->height + (br.height + br.y), r->width + br.width, -(br.height + br.y)};
|
draw_util_rectangle(conn, &(con->frame_buffer), draw_util_colorpixel_to_color(p->color->background),
|
||||||
xcb_poly_fill_rectangle(conn, con->pixmap, con->pm_gc, 1, &bottomline);
|
br.x, r->height + (br.height + br.y), r->width + br.width, -(br.height + br.y));
|
||||||
}
|
}
|
||||||
/* 1pixel border needs an additional line at the top */
|
/* pixel border needs an additional line at the top */
|
||||||
if (p->border_style == BS_PIXEL && !(borders_to_hide & ADJ_UPPER_SCREEN_EDGE)) {
|
if (p->border_style == BS_PIXEL && !(borders_to_hide & ADJ_UPPER_SCREEN_EDGE)) {
|
||||||
xcb_rectangle_t topline = {br.x, 0, r->width + br.width, br.y};
|
draw_util_rectangle(conn, &(con->frame_buffer), draw_util_colorpixel_to_color(p->color->background),
|
||||||
xcb_poly_fill_rectangle(conn, con->pixmap, con->pm_gc, 1, &topline);
|
br.x, 0, r->width + br.width, br.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Highlight the side of the border at which the next window will be
|
/* Highlight the side of the border at which the next window will be
|
||||||
|
@ -463,13 +503,13 @@ void x_draw_decoration(Con *con) {
|
||||||
if (TAILQ_NEXT(con, nodes) == NULL &&
|
if (TAILQ_NEXT(con, nodes) == NULL &&
|
||||||
TAILQ_PREV(con, nodes_head, nodes) == NULL &&
|
TAILQ_PREV(con, nodes_head, nodes) == NULL &&
|
||||||
con->parent->type != CT_FLOATING_CON) {
|
con->parent->type != CT_FLOATING_CON) {
|
||||||
xcb_change_gc(conn, con->pm_gc, XCB_GC_FOREGROUND, (uint32_t[]){p->color->indicator});
|
if (p->parent_layout == L_SPLITH) {
|
||||||
if (p->parent_layout == L_SPLITH)
|
draw_util_rectangle(conn, &(con->frame_buffer), draw_util_colorpixel_to_color(p->color->indicator),
|
||||||
xcb_poly_fill_rectangle(conn, con->pixmap, con->pm_gc, 1, (xcb_rectangle_t[]){
|
r->width + (br.width + br.x), br.y, -(br.width + br.x), r->height + br.height);
|
||||||
{r->width + (br.width + br.x), br.y, -(br.width + br.x), r->height + br.height}});
|
} else if (p->parent_layout == L_SPLITV) {
|
||||||
else if (p->parent_layout == L_SPLITV)
|
draw_util_rectangle(conn, &(con->frame_buffer), draw_util_colorpixel_to_color(p->color->indicator),
|
||||||
xcb_poly_fill_rectangle(conn, con->pixmap, con->pm_gc, 1, (xcb_rectangle_t[]){
|
br.x, r->height + (br.height + br.y), r->width + br.width, -(br.height + br.y));
|
||||||
{br.x, r->height + (br.height + br.y), r->width + br.width, -(br.height + br.y)}});
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -478,31 +518,19 @@ void x_draw_decoration(Con *con) {
|
||||||
if (p->border_style != BS_NORMAL)
|
if (p->border_style != BS_NORMAL)
|
||||||
goto copy_pixmaps;
|
goto copy_pixmaps;
|
||||||
|
|
||||||
|
/* If the parent hasn't been set up yet, skip the decoratin rendering
|
||||||
|
* for now. */
|
||||||
|
if (parent->frame_buffer.id == XCB_NONE)
|
||||||
|
goto copy_pixmaps;
|
||||||
|
|
||||||
/* 4: paint the bar */
|
/* 4: paint the bar */
|
||||||
xcb_change_gc(conn, parent->pm_gc, XCB_GC_FOREGROUND, (uint32_t[]){p->color->background});
|
draw_util_rectangle(conn, &(parent->frame_buffer), draw_util_colorpixel_to_color(p->color->background),
|
||||||
xcb_rectangle_t drect = {con->deco_rect.x, con->deco_rect.y, con->deco_rect.width, con->deco_rect.height};
|
con->deco_rect.x, con->deco_rect.y, con->deco_rect.width, con->deco_rect.height);
|
||||||
xcb_poly_fill_rectangle(conn, parent->pixmap, parent->pm_gc, 1, &drect);
|
|
||||||
|
|
||||||
/* 5: draw two unconnected horizontal lines in border color */
|
/* 5: draw two unconnected horizontal lines in border color */
|
||||||
xcb_change_gc(conn, parent->pm_gc, XCB_GC_FOREGROUND, (uint32_t[]){p->color->border});
|
x_draw_decoration_border(con, p);
|
||||||
Rect *dr = &(con->deco_rect);
|
|
||||||
adjacent_t borders_to_hide = con_adjacent_borders(con) & config.hide_edge_borders;
|
|
||||||
int deco_diff_l = borders_to_hide & ADJ_LEFT_SCREEN_EDGE ? 0 : con->current_border_width;
|
|
||||||
int deco_diff_r = borders_to_hide & ADJ_RIGHT_SCREEN_EDGE ? 0 : con->current_border_width;
|
|
||||||
if (parent->layout == L_TABBED ||
|
|
||||||
(parent->layout == L_STACKED && TAILQ_NEXT(con, nodes) != NULL)) {
|
|
||||||
deco_diff_l = 0;
|
|
||||||
deco_diff_r = 0;
|
|
||||||
}
|
|
||||||
xcb_segment_t segments[] = {
|
|
||||||
{dr->x, dr->y,
|
|
||||||
dr->x + dr->width - 1, dr->y},
|
|
||||||
{dr->x + deco_diff_l, dr->y + dr->height - 1,
|
|
||||||
dr->x - deco_diff_r + dr->width - 1, dr->y + dr->height - 1}};
|
|
||||||
xcb_poly_segment(conn, parent->pixmap, parent->pm_gc, 2, segments);
|
|
||||||
|
|
||||||
/* 6: draw the title */
|
/* 6: draw the title */
|
||||||
set_font_colors(parent->pm_gc, p->color->text, p->color->background);
|
|
||||||
int text_offset_y = (con->deco_rect.height - config.font.height) / 2;
|
int text_offset_y = (con->deco_rect.height - config.font.height) / 2;
|
||||||
|
|
||||||
struct Window *win = con->window;
|
struct Window *win = con->window;
|
||||||
|
@ -510,16 +538,18 @@ void x_draw_decoration(Con *con) {
|
||||||
/* we have a split container which gets a representation
|
/* we have a split container which gets a representation
|
||||||
* of its children as title
|
* of its children as title
|
||||||
*/
|
*/
|
||||||
char *title;
|
char *_title;
|
||||||
char *tree = con_get_tree_representation(con);
|
char *tree = con_get_tree_representation(con);
|
||||||
sasprintf(&title, "i3: %s", tree);
|
sasprintf(&_title, "i3: %s", tree);
|
||||||
free(tree);
|
free(tree);
|
||||||
|
|
||||||
draw_text_ascii(title,
|
i3String *title = i3string_from_utf8(_title);
|
||||||
parent->pixmap, parent->pm_gc,
|
draw_util_text(title, &(parent->frame_buffer),
|
||||||
|
draw_util_colorpixel_to_color(p->color->text), draw_util_colorpixel_to_color(p->color->background),
|
||||||
con->deco_rect.x + 2, con->deco_rect.y + text_offset_y,
|
con->deco_rect.x + 2, con->deco_rect.y + text_offset_y,
|
||||||
con->deco_rect.width - 2);
|
con->deco_rect.width - 2);
|
||||||
free(title);
|
FREE(_title);
|
||||||
|
I3STRING_FREE(title);
|
||||||
|
|
||||||
goto after_title;
|
goto after_title;
|
||||||
}
|
}
|
||||||
|
@ -565,7 +595,8 @@ void x_draw_decoration(Con *con) {
|
||||||
i3String *mark = i3string_from_utf8(formatted_mark);
|
i3String *mark = i3string_from_utf8(formatted_mark);
|
||||||
mark_width = predict_text_width(mark);
|
mark_width = predict_text_width(mark);
|
||||||
|
|
||||||
draw_text(mark, parent->pixmap, parent->pm_gc, NULL,
|
draw_util_text(mark, &(parent->frame_buffer),
|
||||||
|
draw_util_colorpixel_to_color(p->color->text), draw_util_colorpixel_to_color(p->color->background),
|
||||||
con->deco_rect.x + con->deco_rect.width - mark_width - logical_px(2),
|
con->deco_rect.x + con->deco_rect.width - mark_width - logical_px(2),
|
||||||
con->deco_rect.y + text_offset_y, mark_width);
|
con->deco_rect.y + text_offset_y, mark_width);
|
||||||
|
|
||||||
|
@ -576,41 +607,17 @@ void x_draw_decoration(Con *con) {
|
||||||
}
|
}
|
||||||
|
|
||||||
i3String *title = win->title_format == NULL ? win->name : window_parse_title_format(win);
|
i3String *title = win->title_format == NULL ? win->name : window_parse_title_format(win);
|
||||||
draw_text(title,
|
draw_util_text(title, &(parent->frame_buffer),
|
||||||
parent->pixmap, parent->pm_gc, NULL,
|
draw_util_colorpixel_to_color(p->color->text), draw_util_colorpixel_to_color(p->color->background),
|
||||||
con->deco_rect.x + logical_px(2) + indent_px, con->deco_rect.y + text_offset_y,
|
con->deco_rect.x + logical_px(2) + indent_px, con->deco_rect.y + text_offset_y,
|
||||||
con->deco_rect.width - logical_px(2) - indent_px - mark_width - logical_px(2));
|
con->deco_rect.width - logical_px(2) - indent_px - mark_width - logical_px(2));
|
||||||
if (win->title_format != NULL)
|
if (win->title_format != NULL)
|
||||||
I3STRING_FREE(title);
|
I3STRING_FREE(title);
|
||||||
|
|
||||||
after_title:
|
after_title:
|
||||||
/* Since we don’t clip the text at all, it might in some cases be painted
|
x_draw_decoration_after_title(con, p);
|
||||||
* on the border pixels on the right side of a window. Therefore, we draw
|
|
||||||
* the right border again after rendering the text (and the unconnected
|
|
||||||
* lines in border color). */
|
|
||||||
|
|
||||||
/* Draw a 1px separator line before and after every tab, so that tabs can
|
|
||||||
* be easily distinguished. */
|
|
||||||
if (parent->layout == L_TABBED) {
|
|
||||||
xcb_change_gc(conn, parent->pm_gc, XCB_GC_FOREGROUND, (uint32_t[]){p->color->border});
|
|
||||||
} else {
|
|
||||||
xcb_change_gc(conn, parent->pm_gc, XCB_GC_FOREGROUND, (uint32_t[]){p->color->background});
|
|
||||||
}
|
|
||||||
xcb_poly_line(conn, XCB_COORD_MODE_ORIGIN, parent->pixmap, parent->pm_gc, 6,
|
|
||||||
(xcb_point_t[]){
|
|
||||||
{dr->x + dr->width, dr->y},
|
|
||||||
{dr->x + dr->width, dr->y + dr->height},
|
|
||||||
{dr->x + dr->width - 1, dr->y},
|
|
||||||
{dr->x + dr->width - 1, dr->y + dr->height},
|
|
||||||
{dr->x, dr->y + dr->height},
|
|
||||||
{dr->x, dr->y},
|
|
||||||
});
|
|
||||||
|
|
||||||
xcb_change_gc(conn, parent->pm_gc, XCB_GC_FOREGROUND, (uint32_t[]){p->color->border});
|
|
||||||
xcb_poly_segment(conn, parent->pixmap, parent->pm_gc, 2, segments);
|
|
||||||
|
|
||||||
copy_pixmaps:
|
copy_pixmaps:
|
||||||
xcb_copy_area(conn, con->pixmap, con->frame, con->pm_gc, 0, 0, 0, 0, con->rect.width, con->rect.height);
|
draw_util_copy_surface(conn, &(con->frame_buffer), &(con->frame), 0, 0, 0, 0, con->rect.width, con->rect.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -623,7 +630,7 @@ void x_deco_recurse(Con *con) {
|
||||||
Con *current;
|
Con *current;
|
||||||
bool leaf = TAILQ_EMPTY(&(con->nodes_head)) &&
|
bool leaf = TAILQ_EMPTY(&(con->nodes_head)) &&
|
||||||
TAILQ_EMPTY(&(con->floating_head));
|
TAILQ_EMPTY(&(con->floating_head));
|
||||||
con_state *state = state_for_frame(con->frame);
|
con_state *state = state_for_frame(con->frame.id);
|
||||||
|
|
||||||
if (!leaf) {
|
if (!leaf) {
|
||||||
TAILQ_FOREACH(current, &(con->nodes_head), nodes)
|
TAILQ_FOREACH(current, &(con->nodes_head), nodes)
|
||||||
|
@ -632,8 +639,9 @@ void x_deco_recurse(Con *con) {
|
||||||
TAILQ_FOREACH(current, &(con->floating_head), floating_windows)
|
TAILQ_FOREACH(current, &(con->floating_head), floating_windows)
|
||||||
x_deco_recurse(current);
|
x_deco_recurse(current);
|
||||||
|
|
||||||
if (state->mapped)
|
if (state->mapped) {
|
||||||
xcb_copy_area(conn, con->pixmap, con->frame, con->pm_gc, 0, 0, 0, 0, con->rect.width, con->rect.height);
|
draw_util_copy_surface(conn, &(con->frame_buffer), &(con->frame), 0, 0, 0, 0, con->rect.width, con->rect.height);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((con->type != CT_ROOT && con->type != CT_OUTPUT) &&
|
if ((con->type != CT_ROOT && con->type != CT_OUTPUT) &&
|
||||||
|
@ -650,7 +658,7 @@ static void set_hidden_state(Con *con) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
con_state *state = state_for_frame(con->frame);
|
con_state *state = state_for_frame(con->frame.id);
|
||||||
bool should_be_hidden = con_is_hidden(con);
|
bool should_be_hidden = con_is_hidden(con);
|
||||||
if (should_be_hidden == state->is_hidden)
|
if (should_be_hidden == state->is_hidden)
|
||||||
return;
|
return;
|
||||||
|
@ -678,12 +686,12 @@ void x_push_node(Con *con) {
|
||||||
Rect rect = con->rect;
|
Rect rect = con->rect;
|
||||||
|
|
||||||
//DLOG("Pushing changes for node %p / %s\n", con, con->name);
|
//DLOG("Pushing changes for node %p / %s\n", con, con->name);
|
||||||
state = state_for_frame(con->frame);
|
state = state_for_frame(con->frame.id);
|
||||||
|
|
||||||
if (state->name != NULL) {
|
if (state->name != NULL) {
|
||||||
DLOG("pushing name %s for con %p\n", state->name, con);
|
DLOG("pushing name %s for con %p\n", state->name, con);
|
||||||
|
|
||||||
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, con->frame,
|
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, con->frame.id,
|
||||||
XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, strlen(state->name), state->name);
|
XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, strlen(state->name), state->name);
|
||||||
FREE(state->name);
|
FREE(state->name);
|
||||||
}
|
}
|
||||||
|
@ -716,7 +724,7 @@ void x_push_node(Con *con) {
|
||||||
xcb_change_window_attributes(conn, state->old_frame, XCB_CW_EVENT_MASK, values);
|
xcb_change_window_attributes(conn, state->old_frame, XCB_CW_EVENT_MASK, values);
|
||||||
xcb_change_window_attributes(conn, con->window->id, XCB_CW_EVENT_MASK, values);
|
xcb_change_window_attributes(conn, con->window->id, XCB_CW_EVENT_MASK, values);
|
||||||
|
|
||||||
xcb_reparent_window(conn, con->window->id, con->frame, 0, 0);
|
xcb_reparent_window(conn, con->window->id, con->frame.id, 0, 0);
|
||||||
|
|
||||||
values[0] = FRAME_EVENT_MASK;
|
values[0] = FRAME_EVENT_MASK;
|
||||||
xcb_change_window_attributes(conn, state->old_frame, XCB_CW_EVENT_MASK, values);
|
xcb_change_window_attributes(conn, state->old_frame, XCB_CW_EVENT_MASK, values);
|
||||||
|
@ -741,7 +749,7 @@ void x_push_node(Con *con) {
|
||||||
bool fake_notify = false;
|
bool fake_notify = false;
|
||||||
/* Set new position if rect changed (and if height > 0) or if the pixmap
|
/* Set new position if rect changed (and if height > 0) or if the pixmap
|
||||||
* needs to be recreated */
|
* needs to be recreated */
|
||||||
if ((is_pixmap_needed && con->pixmap == XCB_NONE) || (memcmp(&(state->rect), &rect, sizeof(Rect)) != 0 &&
|
if ((is_pixmap_needed && con->frame_buffer.id == XCB_NONE) || (memcmp(&(state->rect), &rect, sizeof(Rect)) != 0 &&
|
||||||
rect.height > 0)) {
|
rect.height > 0)) {
|
||||||
/* We first create the new pixmap, then render to it, set it as the
|
/* We first create the new pixmap, then render to it, set it as the
|
||||||
* background and only afterwards change the window size. This reduces
|
* background and only afterwards change the window size. This reduces
|
||||||
|
@ -755,38 +763,47 @@ void x_push_node(Con *con) {
|
||||||
|
|
||||||
/* Check if the container has an unneeded pixmap left over from
|
/* Check if the container has an unneeded pixmap left over from
|
||||||
* previously having a border or titlebar. */
|
* previously having a border or titlebar. */
|
||||||
if (!is_pixmap_needed && con->pixmap != XCB_NONE) {
|
if (!is_pixmap_needed && con->frame_buffer.id != XCB_NONE) {
|
||||||
xcb_free_pixmap(conn, con->pixmap);
|
draw_util_surface_free(conn, &(con->frame_buffer));
|
||||||
con->pixmap = XCB_NONE;
|
xcb_free_pixmap(conn, con->frame_buffer.id);
|
||||||
|
con->frame_buffer.id = XCB_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_pixmap_needed && (has_rect_changed || con->pixmap == XCB_NONE)) {
|
if (is_pixmap_needed && (has_rect_changed || con->frame_buffer.id == XCB_NONE)) {
|
||||||
if (con->pixmap == 0) {
|
if (con->frame_buffer.id == XCB_NONE) {
|
||||||
con->pixmap = xcb_generate_id(conn);
|
con->frame_buffer.id = xcb_generate_id(conn);
|
||||||
con->pm_gc = xcb_generate_id(conn);
|
|
||||||
} else {
|
} else {
|
||||||
xcb_free_pixmap(conn, con->pixmap);
|
draw_util_surface_free(conn, &(con->frame_buffer));
|
||||||
xcb_free_gc(conn, con->pm_gc);
|
xcb_free_pixmap(conn, con->frame_buffer.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t win_depth = root_depth;
|
uint16_t win_depth = root_depth;
|
||||||
if (con->window)
|
if (con->window)
|
||||||
win_depth = con->window->depth;
|
win_depth = con->window->depth;
|
||||||
|
|
||||||
xcb_create_pixmap(conn, win_depth, con->pixmap, con->frame, rect.width, rect.height);
|
/* Ensure we have valid dimensions for our surface. */
|
||||||
|
// TODO This is probably a bug in the condition above as we should never enter this path
|
||||||
|
// for height == 0. Also, we should probably handle width == 0 the same way.
|
||||||
|
int width = MAX(rect.width, 1);
|
||||||
|
int height = MAX(rect.height, 1);
|
||||||
|
|
||||||
|
xcb_create_pixmap_checked(conn, win_depth, con->frame_buffer.id, con->frame.id, width, height);
|
||||||
|
draw_util_surface_init(conn, &(con->frame_buffer), con->frame_buffer.id,
|
||||||
|
get_visualtype_by_id(get_visualid_by_depth(win_depth)), width, height);
|
||||||
|
|
||||||
/* For the graphics context, we disable GraphicsExposure events.
|
/* For the graphics context, we disable GraphicsExposure events.
|
||||||
* Those will be sent when a CopyArea request cannot be fulfilled
|
* Those will be sent when a CopyArea request cannot be fulfilled
|
||||||
* properly due to parts of the source being unmapped or otherwise
|
* properly due to parts of the source being unmapped or otherwise
|
||||||
* unavailable. Since we always copy from pixmaps to windows, this
|
* unavailable. Since we always copy from pixmaps to windows, this
|
||||||
* is not a concern for us. */
|
* is not a concern for us. */
|
||||||
uint32_t values[] = {0};
|
xcb_change_gc(conn, con->frame_buffer.gc, XCB_GC_GRAPHICS_EXPOSURES, (uint32_t[]){0});
|
||||||
xcb_create_gc(conn, con->pm_gc, con->pixmap, XCB_GC_GRAPHICS_EXPOSURES, values);
|
|
||||||
|
|
||||||
|
draw_util_surface_set_size(&(con->frame), width, height);
|
||||||
con->pixmap_recreated = true;
|
con->pixmap_recreated = true;
|
||||||
|
|
||||||
/* Don’t render the decoration for windows inside a stack which are
|
/* Don’t render the decoration for windows inside a stack which are
|
||||||
* not visible right now */
|
* not visible right now */
|
||||||
|
// TODO Should this work the same way for L_TABBED?
|
||||||
if (!con->parent ||
|
if (!con->parent ||
|
||||||
con->parent->layout != L_STACKED ||
|
con->parent->layout != L_STACKED ||
|
||||||
TAILQ_FIRST(&(con->parent->focus_head)) == con)
|
TAILQ_FIRST(&(con->parent->focus_head)) == con)
|
||||||
|
@ -802,9 +819,10 @@ void x_push_node(Con *con) {
|
||||||
* window get lost when resizing it, therefore we want to provide it as
|
* window get lost when resizing it, therefore we want to provide it as
|
||||||
* fast as possible) */
|
* fast as possible) */
|
||||||
xcb_flush(conn);
|
xcb_flush(conn);
|
||||||
xcb_set_window_rect(conn, con->frame, rect);
|
xcb_set_window_rect(conn, con->frame.id, rect);
|
||||||
if (con->pixmap != XCB_NONE)
|
if (con->frame_buffer.id != XCB_NONE) {
|
||||||
xcb_copy_area(conn, con->pixmap, con->frame, con->pm_gc, 0, 0, 0, 0, con->rect.width, con->rect.height);
|
draw_util_copy_surface(conn, &(con->frame_buffer), &(con->frame), 0, 0, 0, 0, con->rect.width, con->rect.height);
|
||||||
|
}
|
||||||
xcb_flush(conn);
|
xcb_flush(conn);
|
||||||
|
|
||||||
memcpy(&(state->rect), &rect, sizeof(Rect));
|
memcpy(&(state->rect), &rect, sizeof(Rect));
|
||||||
|
@ -848,17 +866,18 @@ void x_push_node(Con *con) {
|
||||||
state->child_mapped = true;
|
state->child_mapped = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
cookie = xcb_map_window(conn, con->frame);
|
cookie = xcb_map_window(conn, con->frame.id);
|
||||||
|
|
||||||
values[0] = FRAME_EVENT_MASK;
|
values[0] = FRAME_EVENT_MASK;
|
||||||
xcb_change_window_attributes(conn, con->frame, XCB_CW_EVENT_MASK, values);
|
xcb_change_window_attributes(conn, con->frame.id, XCB_CW_EVENT_MASK, values);
|
||||||
|
|
||||||
/* copy the pixmap contents to the frame window immediately after mapping */
|
/* copy the pixmap contents to the frame window immediately after mapping */
|
||||||
if (con->pixmap != XCB_NONE)
|
if (con->frame_buffer.id != XCB_NONE) {
|
||||||
xcb_copy_area(conn, con->pixmap, con->frame, con->pm_gc, 0, 0, 0, 0, con->rect.width, con->rect.height);
|
draw_util_copy_surface(conn, &(con->frame_buffer), &(con->frame), 0, 0, 0, 0, con->rect.width, con->rect.height);
|
||||||
|
}
|
||||||
xcb_flush(conn);
|
xcb_flush(conn);
|
||||||
|
|
||||||
DLOG("mapping container %08x (serial %d)\n", con->frame, cookie.sequence);
|
DLOG("mapping container %08x (serial %d)\n", con->frame.id, cookie.sequence);
|
||||||
state->mapped = con->mapped;
|
state->mapped = con->mapped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -892,7 +911,7 @@ static void x_push_node_unmaps(Con *con) {
|
||||||
con_state *state;
|
con_state *state;
|
||||||
|
|
||||||
//DLOG("Pushing changes (with unmaps) for node %p / %s\n", con, con->name);
|
//DLOG("Pushing changes (with unmaps) for node %p / %s\n", con, con->name);
|
||||||
state = state_for_frame(con->frame);
|
state = state_for_frame(con->frame.id);
|
||||||
|
|
||||||
/* map/unmap if map state changed, also ensure that the child window
|
/* map/unmap if map state changed, also ensure that the child window
|
||||||
* is changed if we are mapped *and* in initial state (meaning the
|
* is changed if we are mapped *and* in initial state (meaning the
|
||||||
|
@ -906,14 +925,14 @@ static void x_push_node_unmaps(Con *con) {
|
||||||
A_WM_STATE, A_WM_STATE, 32, 2, data);
|
A_WM_STATE, A_WM_STATE, 32, 2, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
cookie = xcb_unmap_window(conn, con->frame);
|
cookie = xcb_unmap_window(conn, con->frame.id);
|
||||||
DLOG("unmapping container %p / %s (serial %d)\n", con, con->name, cookie.sequence);
|
DLOG("unmapping container %p / %s (serial %d)\n", con, con->name, cookie.sequence);
|
||||||
/* we need to increase ignore_unmap for this container (if it
|
/* we need to increase ignore_unmap for this container (if it
|
||||||
* contains a window) and for every window "under" this one which
|
* contains a window) and for every window "under" this one which
|
||||||
* contains a window */
|
* contains a window */
|
||||||
if (con->window != NULL) {
|
if (con->window != NULL) {
|
||||||
con->ignore_unmap++;
|
con->ignore_unmap++;
|
||||||
DLOG("ignore_unmap for con %p (frame 0x%08x) now %d\n", con, con->frame, con->ignore_unmap);
|
DLOG("ignore_unmap for con %p (frame 0x%08x) now %d\n", con, con->frame.id, con->ignore_unmap);
|
||||||
}
|
}
|
||||||
state->mapped = con->mapped;
|
state->mapped = con->mapped;
|
||||||
}
|
}
|
||||||
|
@ -1067,7 +1086,7 @@ void x_push_changes(Con *con) {
|
||||||
|
|
||||||
x_deco_recurse(con);
|
x_deco_recurse(con);
|
||||||
|
|
||||||
xcb_window_t to_focus = focused->frame;
|
xcb_window_t to_focus = focused->frame.id;
|
||||||
if (focused->window != NULL)
|
if (focused->window != NULL)
|
||||||
to_focus = focused->window->id;
|
to_focus = focused->window->id;
|
||||||
|
|
||||||
|
@ -1161,7 +1180,7 @@ void x_push_changes(Con *con) {
|
||||||
*/
|
*/
|
||||||
void x_raise_con(Con *con) {
|
void x_raise_con(Con *con) {
|
||||||
con_state *state;
|
con_state *state;
|
||||||
state = state_for_frame(con->frame);
|
state = state_for_frame(con->frame.id);
|
||||||
//DLOG("raising in new stack: %p / %s / %s / xid %08x\n", con, con->name, con->window ? con->window->name_json : "", state->id);
|
//DLOG("raising in new stack: %p / %s / %s / xid %08x\n", con, con->name, con->window ? con->window->name_json : "", state->id);
|
||||||
|
|
||||||
CIRCLEQ_REMOVE(&state_head, state, state);
|
CIRCLEQ_REMOVE(&state_head, state, state);
|
||||||
|
@ -1177,7 +1196,7 @@ void x_raise_con(Con *con) {
|
||||||
void x_set_name(Con *con, const char *name) {
|
void x_set_name(Con *con, const char *name) {
|
||||||
struct con_state *state;
|
struct con_state *state;
|
||||||
|
|
||||||
if ((state = state_for_frame(con->frame)) == NULL) {
|
if ((state = state_for_frame(con->frame.id)) == NULL) {
|
||||||
ELOG("window state not found\n");
|
ELOG("window state not found\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
16
src/xcb.c
16
src/xcb.c
|
@ -252,6 +252,22 @@ uint16_t get_visual_depth(xcb_visualid_t visual_id) {
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
xcb_visualtype_t *get_visualtype_by_id(xcb_visualid_t visual_id) {
|
||||||
|
xcb_depth_iterator_t depth_iter;
|
||||||
|
|
||||||
|
depth_iter = xcb_screen_allowed_depths_iterator(root_screen);
|
||||||
|
for (; depth_iter.rem; xcb_depth_next(&depth_iter)) {
|
||||||
|
xcb_visualtype_iterator_t visual_iter;
|
||||||
|
|
||||||
|
visual_iter = xcb_depth_visuals_iterator(depth_iter.data);
|
||||||
|
for (; visual_iter.rem; xcb_visualtype_next(&visual_iter)) {
|
||||||
|
if (visual_id == visual_iter.data->visual_id) {
|
||||||
|
return visual_iter.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get visualid with specified depth
|
* Get visualid with specified depth
|
||||||
|
|
Loading…
Reference in New Issue