Use 32-bit visuals for i3bar when possible and allow RGBA colors.
This patch creates all necessary windows for i3bar with 32-bit visuals if available. It also introduces the possibility to define RGBA colors (next to RGB colors), which allows the user to set the opacity of any color. This requires running a compositor. With this patch we also start supporting _NET_SYSTEM_TRAY_VISUAL, which is necessary for the tray icons so they create the tray window with the correct depth and visual.
This commit is contained in:
parent
ddd5e9a824
commit
1c4100ce5d
|
@ -141,12 +141,12 @@ static int handle_expose(void *data, xcb_connection_t *conn, xcb_expose_event_t
|
||||||
|
|
||||||
/* draw the prompt … */
|
/* draw the prompt … */
|
||||||
if (prompt != NULL) {
|
if (prompt != NULL) {
|
||||||
draw_text(prompt, pixmap, pixmap_gc, logical_px(4), logical_px(4), logical_px(492));
|
draw_text(prompt, pixmap, pixmap_gc, NULL, logical_px(4), logical_px(4), logical_px(492));
|
||||||
}
|
}
|
||||||
/* … and the text */
|
/* … and the text */
|
||||||
if (input_position > 0) {
|
if (input_position > 0) {
|
||||||
i3String *input = i3string_from_ucs2(glyphs_ucs, input_position);
|
i3String *input = i3string_from_ucs2(glyphs_ucs, input_position);
|
||||||
draw_text(input, pixmap, pixmap_gc, prompt_offset + logical_px(4), logical_px(4), logical_px(492));
|
draw_text(input, pixmap, pixmap_gc, NULL, prompt_offset + logical_px(4), logical_px(4), logical_px(492));
|
||||||
i3string_free(input);
|
i3string_free(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -196,7 +196,7 @@ static int handle_expose(xcb_connection_t *conn, xcb_expose_event_t *event) {
|
||||||
|
|
||||||
/* restore font color */
|
/* restore font color */
|
||||||
set_font_colors(pixmap_gc, color_text, color_background);
|
set_font_colors(pixmap_gc, color_text, color_background);
|
||||||
draw_text(prompt, pixmap, pixmap_gc,
|
draw_text(prompt, pixmap, pixmap_gc, NULL,
|
||||||
logical_px(4) + logical_px(4),
|
logical_px(4) + logical_px(4),
|
||||||
logical_px(4) + logical_px(4),
|
logical_px(4) + logical_px(4),
|
||||||
rect.width - logical_px(4) - logical_px(4));
|
rect.width - logical_px(4) - logical_px(4));
|
||||||
|
@ -264,7 +264,7 @@ static int handle_expose(xcb_connection_t *conn, xcb_expose_event_t *event) {
|
||||||
values[1] = color_button_background;
|
values[1] = color_button_background;
|
||||||
set_font_colors(pixmap_gc, color_text, color_button_background);
|
set_font_colors(pixmap_gc, color_text, color_button_background);
|
||||||
/* the x term seems to set left/right padding */
|
/* the x term seems to set left/right padding */
|
||||||
draw_text(buttons[c].label, pixmap, pixmap_gc,
|
draw_text(buttons[c].label, pixmap, pixmap_gc, NULL,
|
||||||
y - w - line_width + logical_px(6),
|
y - w - line_width + logical_px(6),
|
||||||
logical_px(4) + logical_px(3),
|
logical_px(4) + logical_px(3),
|
||||||
rect.width - y + w + line_width - logical_px(6));
|
rect.width - y + w + line_width - logical_px(6));
|
||||||
|
|
|
@ -15,6 +15,7 @@ typedef struct color_t {
|
||||||
double red;
|
double red;
|
||||||
double green;
|
double green;
|
||||||
double blue;
|
double blue;
|
||||||
|
double alpha;
|
||||||
|
|
||||||
/* For compatibility, we also store the colorpixel for now. */
|
/* For compatibility, we also store the colorpixel for now. */
|
||||||
uint32_t colorpixel;
|
uint32_t colorpixel;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
*/
|
*/
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
|
#include <string.h>
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
#include <xcb/xcb_aux.h>
|
#include <xcb/xcb_aux.h>
|
||||||
#include <cairo/cairo-xcb.h>
|
#include <cairo/cairo-xcb.h>
|
||||||
|
@ -16,7 +17,7 @@
|
||||||
#include "libi3.h"
|
#include "libi3.h"
|
||||||
|
|
||||||
xcb_connection_t *xcb_connection;
|
xcb_connection_t *xcb_connection;
|
||||||
xcb_screen_t *root_screen;
|
xcb_visualtype_t *visual_type;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the cairo surface to represent the given drawable.
|
* Initialize the cairo surface to represent the given drawable.
|
||||||
|
@ -30,7 +31,7 @@ void cairo_surface_init(surface_t *surface, xcb_drawable_t drawable, int width,
|
||||||
if (xcb_request_failed(gc_cookie, "Could not create graphical context"))
|
if (xcb_request_failed(gc_cookie, "Could not create graphical context"))
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
|
||||||
surface->surface = cairo_xcb_surface_create(xcb_connection, surface->id, get_visualtype(root_screen), width, height);
|
surface->surface = cairo_xcb_surface_create(xcb_connection, surface->id, visual_type, width, height);
|
||||||
surface->cr = cairo_create(surface->surface);
|
surface->cr = cairo_create(surface->surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,15 +51,25 @@ void cairo_surface_free(surface_t *surface) {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
color_t cairo_hex_to_color(const char *color) {
|
color_t cairo_hex_to_color(const char *color) {
|
||||||
char groups[3][3] = {
|
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] = {
|
||||||
{color[1], color[2], '\0'},
|
{color[1], color[2], '\0'},
|
||||||
{color[3], color[4], '\0'},
|
{color[3], color[4], '\0'},
|
||||||
{color[5], color[6], '\0'}};
|
{color[5], color[6], '\0'},
|
||||||
|
{alpha[0], alpha[1], '\0'}};
|
||||||
|
|
||||||
return (color_t){
|
return (color_t){
|
||||||
.red = strtol(groups[0], NULL, 16) / 255.0,
|
.red = strtol(groups[0], NULL, 16) / 255.0,
|
||||||
.green = strtol(groups[1], NULL, 16) / 255.0,
|
.green = strtol(groups[1], NULL, 16) / 255.0,
|
||||||
.blue = strtol(groups[2], NULL, 16) / 255.0,
|
.blue = strtol(groups[2], NULL, 16) / 255.0,
|
||||||
|
.alpha = strtol(groups[3], NULL, 16) / 255.0,
|
||||||
.colorpixel = get_colorpixel(color)};
|
.colorpixel = get_colorpixel(color)};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,5 +78,5 @@ color_t cairo_hex_to_color(const char *color) {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void cairo_set_source_color(surface_t *surface, color_t color) {
|
void cairo_set_source_color(surface_t *surface, color_t color) {
|
||||||
cairo_set_source_rgb(surface->cr, color.red, color.green, color.blue);
|
cairo_set_source_rgba(surface->cr, color.red, color.green, color.blue, color.alpha);
|
||||||
}
|
}
|
||||||
|
|
121
i3bar/src/xcb.c
121
i3bar/src/xcb.c
|
@ -64,6 +64,10 @@ static i3Font font;
|
||||||
/* Icon size (based on font size) */
|
/* Icon size (based on font size) */
|
||||||
int icon_size;
|
int icon_size;
|
||||||
|
|
||||||
|
xcb_visualtype_t *visual_type;
|
||||||
|
uint8_t depth;
|
||||||
|
xcb_colormap_t colormap;
|
||||||
|
|
||||||
/* Overall height of the bar (based on font size) */
|
/* Overall height of the bar (based on font size) */
|
||||||
int bar_height;
|
int bar_height;
|
||||||
|
|
||||||
|
@ -170,14 +174,17 @@ static void draw_separator(uint32_t x, struct status_block *block) {
|
||||||
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. */
|
||||||
|
cairo_save(statusline_surface.cr);
|
||||||
|
cairo_set_operator(statusline_surface.cr, CAIRO_OPERATOR_SOURCE);
|
||||||
cairo_set_source_color(&statusline_surface, colors.sep_fg);
|
cairo_set_source_color(&statusline_surface, colors.sep_fg);
|
||||||
cairo_rectangle(statusline_surface.cr, center_x, logical_px(sep_voff_px), logical_px(1), bar_height - 2 * logical_px(sep_voff_px));
|
cairo_rectangle(statusline_surface.cr, center_x, logical_px(sep_voff_px), logical_px(1), bar_height - 2 * logical_px(sep_voff_px));
|
||||||
cairo_fill(statusline_surface.cr);
|
cairo_fill(statusline_surface.cr);
|
||||||
|
cairo_restore(statusline_surface.cr);
|
||||||
} else {
|
} else {
|
||||||
/* Draw a custom separator. */
|
/* Draw a custom separator. */
|
||||||
uint32_t separator_x = MAX(x - block->sep_block_width, center_x - separator_symbol_width / 2);
|
uint32_t separator_x = MAX(x - block->sep_block_width, center_x - separator_symbol_width / 2);
|
||||||
set_font_colors(statusline_surface.gc, colors.sep_fg.colorpixel, colors.bar_bg.colorpixel);
|
set_font_colors(statusline_surface.gc, colors.sep_fg.colorpixel, colors.bar_bg.colorpixel);
|
||||||
draw_text(config.separator_symbol, statusline_surface.id, statusline_surface.gc,
|
draw_text(config.separator_symbol, statusline_surface.id, statusline_surface.gc, visual_type,
|
||||||
separator_x, logical_px(ws_voff_px), x - separator_x);
|
separator_x, logical_px(ws_voff_px), x - separator_x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -239,9 +246,11 @@ void refresh_statusline(bool use_short_text) {
|
||||||
realloc_sl_buffer();
|
realloc_sl_buffer();
|
||||||
|
|
||||||
/* Clear the statusline pixmap. */
|
/* Clear the statusline pixmap. */
|
||||||
|
cairo_save(statusline_surface.cr);
|
||||||
cairo_set_source_color(&statusline_surface, colors.bar_bg);
|
cairo_set_source_color(&statusline_surface, colors.bar_bg);
|
||||||
cairo_rectangle(statusline_surface.cr, 0, 0, MAX(root_screen->width_in_pixels, statusline_width), bar_height);
|
cairo_set_operator(statusline_surface.cr, CAIRO_OPERATOR_SOURCE);
|
||||||
cairo_fill(statusline_surface.cr);
|
cairo_paint(statusline_surface.cr);
|
||||||
|
cairo_restore(statusline_surface.cr);
|
||||||
|
|
||||||
/* Draw the text of each block. */
|
/* Draw the text of each block. */
|
||||||
uint32_t x = 0;
|
uint32_t x = 0;
|
||||||
|
@ -263,7 +272,8 @@ void refresh_statusline(bool use_short_text) {
|
||||||
}
|
}
|
||||||
|
|
||||||
set_font_colors(statusline_surface.gc, fg_color.colorpixel, colors.bar_bg.colorpixel);
|
set_font_colors(statusline_surface.gc, fg_color.colorpixel, colors.bar_bg.colorpixel);
|
||||||
draw_text(block->full_text, statusline_surface.id, statusline_surface.gc, x + block->x_offset, logical_px(ws_voff_px), block->width);
|
draw_text(block->full_text, statusline_surface.id, statusline_surface.gc, visual_type,
|
||||||
|
x + block->x_offset, logical_px(ws_voff_px), block->width);
|
||||||
x += block->width + block->sep_block_width + block->x_offset + block->x_append;
|
x += block->width + block->sep_block_width + block->x_offset + block->x_append;
|
||||||
|
|
||||||
/* If this is not the last block, draw a separator. */
|
/* If this is not the last block, draw a separator. */
|
||||||
|
@ -699,11 +709,15 @@ static void handle_client_message(xcb_client_message_event_t *event) {
|
||||||
ELOG("No output found\n");
|
ELOG("No output found\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
xcb_reparent_window(xcb_connection,
|
|
||||||
client,
|
xcb_void_cookie_t rcookie = xcb_reparent_window(xcb_connection,
|
||||||
output->bar.id,
|
client,
|
||||||
output->rect.w - icon_size - logical_px(config.tray_padding),
|
output->bar.id,
|
||||||
logical_px(config.tray_padding));
|
output->rect.w - icon_size - logical_px(config.tray_padding),
|
||||||
|
logical_px(config.tray_padding));
|
||||||
|
if (xcb_request_failed(rcookie, "Could not reparent window. Maybe it is using an incorrect depth/visual?"))
|
||||||
|
return;
|
||||||
|
|
||||||
/* We reconfigure the window to use a reasonable size. The systray
|
/* We reconfigure the window to use a reasonable size. The systray
|
||||||
* specification explicitly says:
|
* specification explicitly says:
|
||||||
* Tray icons may be assigned any size by the system tray, and
|
* Tray icons may be assigned any size by the system tray, and
|
||||||
|
@ -1106,11 +1120,29 @@ char *init_xcb_early() {
|
||||||
root_screen = xcb_aux_get_screen(xcb_connection, screen);
|
root_screen = xcb_aux_get_screen(xcb_connection, screen);
|
||||||
xcb_root = root_screen->root;
|
xcb_root = root_screen->root;
|
||||||
|
|
||||||
|
depth = root_screen->root_depth;
|
||||||
|
colormap = root_screen->default_colormap;
|
||||||
|
visual_type = xcb_aux_find_visual_by_attrs(root_screen, -1, 32);
|
||||||
|
if (visual_type) {
|
||||||
|
depth = xcb_aux_get_depth_of_visual(root_screen, visual_type->visual_id);
|
||||||
|
colormap = xcb_generate_id(xcb_connection);
|
||||||
|
xcb_void_cookie_t cm_cookie = xcb_create_colormap_checked(xcb_connection,
|
||||||
|
XCB_COLORMAP_ALLOC_NONE,
|
||||||
|
colormap,
|
||||||
|
xcb_root,
|
||||||
|
visual_type->visual_id);
|
||||||
|
if (xcb_request_failed(cm_cookie, "Could not allocate colormap")) {
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
visual_type = get_visualtype(root_screen);
|
||||||
|
}
|
||||||
|
|
||||||
/* We draw the statusline to a seperate pixmap, because it looks the same on all bars and
|
/* We draw the statusline to a seperate pixmap, because it looks the same on all bars and
|
||||||
* this way, we can choose to crop it */
|
* this way, we can choose to crop it */
|
||||||
xcb_pixmap_t statusline_id = xcb_generate_id(xcb_connection);
|
xcb_pixmap_t statusline_id = xcb_generate_id(xcb_connection);
|
||||||
xcb_void_cookie_t sl_pm_cookie = xcb_create_pixmap_checked(xcb_connection,
|
xcb_void_cookie_t sl_pm_cookie = xcb_create_pixmap_checked(xcb_connection,
|
||||||
root_screen->root_depth,
|
depth,
|
||||||
statusline_id,
|
statusline_id,
|
||||||
xcb_root,
|
xcb_root,
|
||||||
root_screen->width_in_pixels,
|
root_screen->width_in_pixels,
|
||||||
|
@ -1248,17 +1280,17 @@ void init_tray(void) {
|
||||||
|
|
||||||
/* tray support: we need a window to own the selection */
|
/* tray support: we need a window to own the selection */
|
||||||
selwin = xcb_generate_id(xcb_connection);
|
selwin = xcb_generate_id(xcb_connection);
|
||||||
uint32_t selmask = XCB_CW_OVERRIDE_REDIRECT;
|
uint32_t selmask = XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_COLORMAP;
|
||||||
uint32_t selval[] = {1};
|
uint32_t selval[] = {root_screen->black_pixel, root_screen->black_pixel, 1, colormap};
|
||||||
xcb_create_window(xcb_connection,
|
xcb_create_window(xcb_connection,
|
||||||
root_screen->root_depth,
|
depth,
|
||||||
selwin,
|
selwin,
|
||||||
xcb_root,
|
xcb_root,
|
||||||
-1, -1,
|
-1, -1,
|
||||||
1, 1,
|
1, 1,
|
||||||
0,
|
0,
|
||||||
XCB_WINDOW_CLASS_INPUT_OUTPUT,
|
XCB_WINDOW_CLASS_INPUT_OUTPUT,
|
||||||
root_screen->root_visual,
|
visual_type->visual_id,
|
||||||
selmask,
|
selmask,
|
||||||
selval);
|
selval);
|
||||||
|
|
||||||
|
@ -1272,6 +1304,14 @@ void init_tray(void) {
|
||||||
32,
|
32,
|
||||||
1,
|
1,
|
||||||
&orientation);
|
&orientation);
|
||||||
|
xcb_change_property(xcb_connection,
|
||||||
|
XCB_PROP_MODE_REPLACE,
|
||||||
|
selwin,
|
||||||
|
atoms[_NET_SYSTEM_TRAY_VISUAL],
|
||||||
|
XCB_ATOM_VISUALID,
|
||||||
|
32,
|
||||||
|
1,
|
||||||
|
&visual_type->visual_id);
|
||||||
|
|
||||||
init_tray_colors();
|
init_tray_colors();
|
||||||
|
|
||||||
|
@ -1473,7 +1513,7 @@ void realloc_sl_buffer(void) {
|
||||||
|
|
||||||
xcb_pixmap_t statusline_id = xcb_generate_id(xcb_connection);
|
xcb_pixmap_t statusline_id = xcb_generate_id(xcb_connection);
|
||||||
xcb_void_cookie_t sl_pm_cookie = xcb_create_pixmap_checked(xcb_connection,
|
xcb_void_cookie_t sl_pm_cookie = xcb_create_pixmap_checked(xcb_connection,
|
||||||
root_screen->root_depth,
|
depth,
|
||||||
statusline_id,
|
statusline_id,
|
||||||
xcb_root,
|
xcb_root,
|
||||||
MAX(root_screen->width_in_pixels, statusline_width),
|
MAX(root_screen->width_in_pixels, statusline_width),
|
||||||
|
@ -1551,41 +1591,44 @@ void reconfig_windows(bool redraw_bars) {
|
||||||
|
|
||||||
xcb_window_t bar_id = xcb_generate_id(xcb_connection);
|
xcb_window_t bar_id = xcb_generate_id(xcb_connection);
|
||||||
xcb_pixmap_t buffer_id = xcb_generate_id(xcb_connection);
|
xcb_pixmap_t buffer_id = xcb_generate_id(xcb_connection);
|
||||||
mask = XCB_CW_BACK_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK;
|
mask = XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK | XCB_CW_COLORMAP;
|
||||||
/* Black background */
|
|
||||||
values[0] = colors.bar_bg.colorpixel;
|
values[0] = colors.bar_bg.colorpixel;
|
||||||
|
values[1] = root_screen->black_pixel;
|
||||||
/* If hide_on_modifier is set to hide or invisible mode, i3 is not supposed to manage our bar windows */
|
/* If hide_on_modifier is set to hide or invisible mode, i3 is not supposed to manage our bar windows */
|
||||||
values[1] = (config.hide_on_modifier == M_DOCK ? 0 : 1);
|
values[2] = (config.hide_on_modifier == M_DOCK ? 0 : 1);
|
||||||
/* We enable the following EventMask fields:
|
/* We enable the following EventMask fields:
|
||||||
* EXPOSURE, to get expose events (we have to re-draw then)
|
* EXPOSURE, to get expose events (we have to re-draw then)
|
||||||
* SUBSTRUCTURE_REDIRECT, to get ConfigureRequests when the tray
|
* SUBSTRUCTURE_REDIRECT, to get ConfigureRequests when the tray
|
||||||
* child windows use ConfigureWindow
|
* child windows use ConfigureWindow
|
||||||
* BUTTON_PRESS, to handle clicks on the workspace buttons
|
* BUTTON_PRESS, to handle clicks on the workspace buttons
|
||||||
* */
|
* */
|
||||||
values[2] = XCB_EVENT_MASK_EXPOSURE |
|
values[3] = XCB_EVENT_MASK_EXPOSURE |
|
||||||
XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
|
XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
|
||||||
XCB_EVENT_MASK_BUTTON_PRESS;
|
XCB_EVENT_MASK_BUTTON_PRESS;
|
||||||
if (config.hide_on_modifier == M_DOCK) {
|
if (config.hide_on_modifier == M_DOCK) {
|
||||||
/* If the bar is normally visible, catch visibility change events to suspend
|
/* If the bar is normally visible, catch visibility change events to suspend
|
||||||
* the status process when the bar is obscured by full-screened windows. */
|
* the status process when the bar is obscured by full-screened windows. */
|
||||||
values[2] |= XCB_EVENT_MASK_VISIBILITY_CHANGE;
|
values[3] |= XCB_EVENT_MASK_VISIBILITY_CHANGE;
|
||||||
walk->visible = true;
|
walk->visible = true;
|
||||||
}
|
}
|
||||||
|
values[4] = colormap;
|
||||||
|
|
||||||
xcb_void_cookie_t win_cookie = xcb_create_window_checked(xcb_connection,
|
xcb_void_cookie_t win_cookie = xcb_create_window_checked(xcb_connection,
|
||||||
root_screen->root_depth,
|
depth,
|
||||||
bar_id,
|
bar_id,
|
||||||
xcb_root,
|
xcb_root,
|
||||||
walk->rect.x, walk->rect.y + walk->rect.h - bar_height,
|
walk->rect.x, walk->rect.y + walk->rect.h - bar_height,
|
||||||
walk->rect.w, bar_height,
|
walk->rect.w, bar_height,
|
||||||
0,
|
0,
|
||||||
XCB_WINDOW_CLASS_INPUT_OUTPUT,
|
XCB_WINDOW_CLASS_INPUT_OUTPUT,
|
||||||
root_screen->root_visual,
|
visual_type->visual_id,
|
||||||
mask,
|
mask,
|
||||||
values);
|
values);
|
||||||
|
|
||||||
/* The double-buffer we use to render stuff off-screen */
|
/* The double-buffer we use to render stuff off-screen */
|
||||||
xcb_void_cookie_t pm_cookie = xcb_create_pixmap_checked(xcb_connection,
|
xcb_void_cookie_t pm_cookie = xcb_create_pixmap_checked(xcb_connection,
|
||||||
root_screen->root_depth,
|
depth,
|
||||||
buffer_id,
|
buffer_id,
|
||||||
bar_id,
|
bar_id,
|
||||||
walk->rect.w,
|
walk->rect.w,
|
||||||
|
@ -1701,7 +1744,7 @@ void reconfig_windows(bool redraw_bars) {
|
||||||
|
|
||||||
DLOG("Recreating buffer for output %s\n", walk->name);
|
DLOG("Recreating buffer for output %s\n", walk->name);
|
||||||
xcb_void_cookie_t pm_cookie = xcb_create_pixmap_checked(xcb_connection,
|
xcb_void_cookie_t pm_cookie = xcb_create_pixmap_checked(xcb_connection,
|
||||||
root_screen->root_depth,
|
depth,
|
||||||
walk->buffer.id,
|
walk->buffer.id,
|
||||||
walk->bar.id,
|
walk->bar.id,
|
||||||
walk->rect.w,
|
walk->rect.w,
|
||||||
|
@ -1766,10 +1809,13 @@ void draw_bars(bool unhide) {
|
||||||
/* Oh shit, an active output without an own bar. Create it now! */
|
/* Oh shit, an active output without an own bar. Create it now! */
|
||||||
reconfig_windows(false);
|
reconfig_windows(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* First things first: clear the backbuffer */
|
/* First things first: clear the backbuffer */
|
||||||
|
cairo_save(outputs_walk->buffer.cr);
|
||||||
cairo_set_source_color(&(outputs_walk->buffer), colors.bar_bg);
|
cairo_set_source_color(&(outputs_walk->buffer), colors.bar_bg);
|
||||||
cairo_rectangle(outputs_walk->buffer.cr, 0, 0, outputs_walk->rect.w, bar_height);
|
cairo_set_operator(outputs_walk->buffer.cr, CAIRO_OPERATOR_SOURCE);
|
||||||
cairo_fill(outputs_walk->buffer.cr);
|
cairo_paint(outputs_walk->buffer.cr);
|
||||||
|
cairo_restore(outputs_walk->buffer.cr);
|
||||||
|
|
||||||
if (!config.disable_ws) {
|
if (!config.disable_ws) {
|
||||||
i3_ws *ws_walk;
|
i3_ws *ws_walk;
|
||||||
|
@ -1798,20 +1844,27 @@ void draw_bars(bool unhide) {
|
||||||
unhide = true;
|
unhide = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cairo_save(outputs_walk->buffer.cr);
|
||||||
|
cairo_set_operator(outputs_walk->buffer.cr, CAIRO_OPERATOR_SOURCE);
|
||||||
|
|
||||||
|
/* Draw the border of the button. */
|
||||||
cairo_set_source_color(&(outputs_walk->buffer), border_color);
|
cairo_set_source_color(&(outputs_walk->buffer), border_color);
|
||||||
cairo_rectangle(outputs_walk->buffer.cr, workspace_width, logical_px(1),
|
cairo_rectangle(outputs_walk->buffer.cr, workspace_width, 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));
|
||||||
cairo_fill(outputs_walk->buffer.cr);
|
cairo_fill(outputs_walk->buffer.cr);
|
||||||
|
|
||||||
|
/* Draw the inside of the button. */
|
||||||
cairo_set_source_color(&(outputs_walk->buffer), bg_color);
|
cairo_set_source_color(&(outputs_walk->buffer), bg_color);
|
||||||
cairo_rectangle(outputs_walk->buffer.cr, workspace_width + logical_px(1), 2 * logical_px(1),
|
cairo_rectangle(outputs_walk->buffer.cr, workspace_width + 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),
|
||||||
font.height + 2 * logical_px(ws_voff_px) - 4 * logical_px(1));
|
font.height + 2 * logical_px(ws_voff_px) - 4 * logical_px(1));
|
||||||
cairo_fill(outputs_walk->buffer.cr);
|
cairo_fill(outputs_walk->buffer.cr);
|
||||||
|
|
||||||
|
cairo_restore(outputs_walk->buffer.cr);
|
||||||
|
|
||||||
set_font_colors(outputs_walk->buffer.gc, fg_color.colorpixel, bg_color.colorpixel);
|
set_font_colors(outputs_walk->buffer.gc, fg_color.colorpixel, bg_color.colorpixel);
|
||||||
draw_text(ws_walk->name, outputs_walk->buffer.id, outputs_walk->buffer.gc,
|
draw_text(ws_walk->name, outputs_walk->buffer.id, outputs_walk->buffer.gc, visual_type,
|
||||||
workspace_width + logical_px(ws_hoff_px) + logical_px(1),
|
workspace_width + logical_px(ws_hoff_px) + logical_px(1),
|
||||||
logical_px(ws_voff_px),
|
logical_px(ws_voff_px),
|
||||||
ws_walk->name_width);
|
ws_walk->name_width);
|
||||||
|
@ -1828,6 +1881,9 @@ 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;
|
||||||
|
|
||||||
|
cairo_save(outputs_walk->buffer.cr);
|
||||||
|
cairo_set_operator(outputs_walk->buffer.cr, CAIRO_OPERATOR_SOURCE);
|
||||||
|
|
||||||
cairo_set_source_color(&(outputs_walk->buffer), colors.binding_mode_border);
|
cairo_set_source_color(&(outputs_walk->buffer), colors.binding_mode_border);
|
||||||
cairo_rectangle(outputs_walk->buffer.cr, workspace_width, logical_px(1),
|
cairo_rectangle(outputs_walk->buffer.cr, workspace_width, 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),
|
||||||
|
@ -1840,10 +1896,13 @@ void draw_bars(bool unhide) {
|
||||||
font.height + 2 * logical_px(ws_voff_px) - 4 * logical_px(1));
|
font.height + 2 * logical_px(ws_voff_px) - 4 * logical_px(1));
|
||||||
cairo_fill(outputs_walk->buffer.cr);
|
cairo_fill(outputs_walk->buffer.cr);
|
||||||
|
|
||||||
|
cairo_restore(outputs_walk->buffer.cr);
|
||||||
|
|
||||||
set_font_colors(outputs_walk->buffer.gc, fg_color.colorpixel, bg_color.colorpixel);
|
set_font_colors(outputs_walk->buffer.gc, fg_color.colorpixel, bg_color.colorpixel);
|
||||||
draw_text(binding.name,
|
draw_text(binding.name,
|
||||||
outputs_walk->buffer.id,
|
outputs_walk->buffer.id,
|
||||||
outputs_walk->buffer.gc,
|
outputs_walk->buffer.gc,
|
||||||
|
visual_type,
|
||||||
workspace_width + logical_px(ws_hoff_px) + logical_px(1),
|
workspace_width + logical_px(ws_hoff_px) + logical_px(1),
|
||||||
logical_px(ws_voff_px),
|
logical_px(ws_voff_px),
|
||||||
binding.width);
|
binding.width);
|
||||||
|
@ -1876,9 +1935,12 @@ void draw_bars(bool unhide) {
|
||||||
int x_src = (int16_t)(statusline_width - visible_statusline_width);
|
int x_src = (int16_t)(statusline_width - visible_statusline_width);
|
||||||
int x_dest = (int16_t)(outputs_walk->rect.w - tray_width - logical_px(sb_hoff_px) - visible_statusline_width);
|
int x_dest = (int16_t)(outputs_walk->rect.w - tray_width - logical_px(sb_hoff_px) - visible_statusline_width);
|
||||||
|
|
||||||
|
cairo_save(outputs_walk->buffer.cr);
|
||||||
|
cairo_set_operator(outputs_walk->buffer.cr, CAIRO_OPERATOR_SOURCE);
|
||||||
cairo_set_source_surface(outputs_walk->buffer.cr, statusline_surface.surface, x_dest - x_src, 0);
|
cairo_set_source_surface(outputs_walk->buffer.cr, statusline_surface.surface, x_dest - x_src, 0);
|
||||||
cairo_rectangle(outputs_walk->buffer.cr, x_dest, 0, (int16_t)visible_statusline_width, (int16_t)bar_height);
|
cairo_rectangle(outputs_walk->buffer.cr, x_dest, 0, (int16_t)visible_statusline_width, (int16_t)bar_height);
|
||||||
cairo_fill(outputs_walk->buffer.cr);
|
cairo_fill(outputs_walk->buffer.cr);
|
||||||
|
cairo_restore(outputs_walk->buffer.cr);
|
||||||
}
|
}
|
||||||
|
|
||||||
workspace_width = 0;
|
workspace_width = 0;
|
||||||
|
@ -1906,9 +1968,14 @@ void redraw_bars(void) {
|
||||||
if (!outputs_walk->active) {
|
if (!outputs_walk->active) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cairo_save(outputs_walk->bar.cr);
|
||||||
|
cairo_set_operator(outputs_walk->bar.cr, CAIRO_OPERATOR_SOURCE);
|
||||||
cairo_set_source_surface(outputs_walk->bar.cr, outputs_walk->buffer.surface, 0, 0);
|
cairo_set_source_surface(outputs_walk->bar.cr, outputs_walk->buffer.surface, 0, 0);
|
||||||
cairo_rectangle(outputs_walk->bar.cr, 0, 0, outputs_walk->rect.w, outputs_walk->rect.h);
|
cairo_rectangle(outputs_walk->bar.cr, 0, 0, outputs_walk->rect.w, outputs_walk->rect.h);
|
||||||
cairo_fill(outputs_walk->bar.cr);
|
cairo_fill(outputs_walk->bar.cr);
|
||||||
|
cairo_restore(outputs_walk->bar.cr);
|
||||||
|
|
||||||
xcb_flush(xcb_connection);
|
xcb_flush(xcb_connection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -402,8 +402,8 @@ bool font_is_pango(void);
|
||||||
* Text must be specified as an i3String.
|
* Text must be specified as an i3String.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void draw_text(i3String *text, xcb_drawable_t drawable,
|
void draw_text(i3String *text, xcb_drawable_t drawable, xcb_gcontext_t gc,
|
||||||
xcb_gcontext_t gc, int x, int y, int max_width);
|
xcb_visualtype_t *visual, int x, int y, int max_width);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ASCII version of draw_text to print static strings.
|
* ASCII version of draw_text to print static strings.
|
||||||
|
|
17
libi3/font.c
17
libi3/font.c
|
@ -102,12 +102,12 @@ static bool load_pango_font(i3Font *font, const char *desc) {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static void draw_text_pango(const char *text, size_t text_len,
|
static void draw_text_pango(const char *text, size_t text_len,
|
||||||
xcb_drawable_t drawable, int x, int y,
|
xcb_drawable_t drawable, xcb_visualtype_t *visual, int x, int y,
|
||||||
int max_width, bool is_markup) {
|
int max_width, bool is_markup) {
|
||||||
/* Create the Pango layout */
|
/* Create the Pango layout */
|
||||||
/* root_visual_type is cached in load_pango_font */
|
/* root_visual_type is cached in load_pango_font */
|
||||||
cairo_surface_t *surface = cairo_xcb_surface_create(conn, drawable,
|
cairo_surface_t *surface = cairo_xcb_surface_create(conn, drawable,
|
||||||
root_visual_type, x + max_width, y + savedFont->height);
|
visual, x + max_width, y + savedFont->height);
|
||||||
cairo_t *cr = cairo_create(surface);
|
cairo_t *cr = cairo_create(surface);
|
||||||
PangoLayout *layout = create_layout_with_dpi(cr);
|
PangoLayout *layout = create_layout_with_dpi(cr);
|
||||||
gint height;
|
gint height;
|
||||||
|
@ -391,9 +391,12 @@ static void draw_text_xcb(const xcb_char2b_t *text, size_t text_len, xcb_drawabl
|
||||||
* Text must be specified as an i3String.
|
* Text must be specified as an i3String.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void draw_text(i3String *text, xcb_drawable_t drawable,
|
void draw_text(i3String *text, xcb_drawable_t drawable, xcb_gcontext_t gc,
|
||||||
xcb_gcontext_t gc, int x, int y, int max_width) {
|
xcb_visualtype_t *visual, int x, int y, int max_width) {
|
||||||
assert(savedFont != NULL);
|
assert(savedFont != NULL);
|
||||||
|
if (visual == NULL) {
|
||||||
|
visual = root_visual_type;
|
||||||
|
}
|
||||||
|
|
||||||
switch (savedFont->type) {
|
switch (savedFont->type) {
|
||||||
case FONT_TYPE_NONE:
|
case FONT_TYPE_NONE:
|
||||||
|
@ -407,7 +410,7 @@ void draw_text(i3String *text, xcb_drawable_t drawable,
|
||||||
case FONT_TYPE_PANGO:
|
case FONT_TYPE_PANGO:
|
||||||
/* Render the text using Pango */
|
/* Render the text using Pango */
|
||||||
draw_text_pango(i3string_as_utf8(text), i3string_get_num_bytes(text),
|
draw_text_pango(i3string_as_utf8(text), i3string_get_num_bytes(text),
|
||||||
drawable, x, y, max_width, i3string_is_markup(text));
|
drawable, visual, x, y, max_width, i3string_is_markup(text));
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
|
@ -432,7 +435,7 @@ void draw_text_ascii(const char *text, xcb_drawable_t drawable,
|
||||||
if (text_len > 255) {
|
if (text_len > 255) {
|
||||||
/* The text is too long to draw it directly to X */
|
/* The text is too long to draw it directly to X */
|
||||||
i3String *str = i3string_from_utf8(text);
|
i3String *str = i3string_from_utf8(text);
|
||||||
draw_text(str, drawable, gc, x, y, max_width);
|
draw_text(str, drawable, gc, NULL, x, y, max_width);
|
||||||
i3string_free(str);
|
i3string_free(str);
|
||||||
} else {
|
} else {
|
||||||
/* X11 coordinates for fonts start at the baseline */
|
/* X11 coordinates for fonts start at the baseline */
|
||||||
|
@ -446,7 +449,7 @@ void draw_text_ascii(const char *text, xcb_drawable_t drawable,
|
||||||
case FONT_TYPE_PANGO:
|
case FONT_TYPE_PANGO:
|
||||||
/* Render the text using Pango */
|
/* Render the text using Pango */
|
||||||
draw_text_pango(text, strlen(text),
|
draw_text_pango(text, strlen(text),
|
||||||
drawable, x, y, max_width, false);
|
drawable, root_visual_type, x, y, max_width, false);
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -161,7 +161,7 @@ static void update_placeholder_contents(placeholder_state *state) {
|
||||||
DLOG("con %p (placeholder 0x%08x) line %d: %s\n", state->con, state->window, n, serialized);
|
DLOG("con %p (placeholder 0x%08x) line %d: %s\n", state->con, state->window, n, serialized);
|
||||||
|
|
||||||
i3String *str = i3string_from_utf8(serialized);
|
i3String *str = i3string_from_utf8(serialized);
|
||||||
draw_text(str, state->pixmap, state->gc, 2, (n * (config.font.height + 2)) + 2, state->rect.width - 2);
|
draw_text(str, state->pixmap, state->gc, NULL, 2, (n * (config.font.height + 2)) + 2, state->rect.width - 2);
|
||||||
i3string_free(str);
|
i3string_free(str);
|
||||||
n++;
|
n++;
|
||||||
free(serialized);
|
free(serialized);
|
||||||
|
@ -172,7 +172,7 @@ static void update_placeholder_contents(placeholder_state *state) {
|
||||||
int text_width = predict_text_width(line);
|
int text_width = predict_text_width(line);
|
||||||
int x = (state->rect.width / 2) - (text_width / 2);
|
int x = (state->rect.width / 2) - (text_width / 2);
|
||||||
int y = (state->rect.height / 2) - (config.font.height / 2);
|
int y = (state->rect.height / 2) - (config.font.height / 2);
|
||||||
draw_text(line, state->pixmap, state->gc, x, y, text_width);
|
draw_text(line, state->pixmap, state->gc, NULL, x, y, text_width);
|
||||||
i3string_free(line);
|
i3string_free(line);
|
||||||
xcb_flush(conn);
|
xcb_flush(conn);
|
||||||
xcb_aux_sync(conn);
|
xcb_aux_sync(conn);
|
||||||
|
|
|
@ -154,7 +154,7 @@ static int sig_draw_window(xcb_window_t win, int width, int height, int font_hei
|
||||||
if (i == backtrace_string_index)
|
if (i == backtrace_string_index)
|
||||||
set_font_colors(pixmap_gc, get_colorpixel(bt_colour), get_colorpixel("#000000"));
|
set_font_colors(pixmap_gc, get_colorpixel(bt_colour), get_colorpixel("#000000"));
|
||||||
|
|
||||||
draw_text(crash_text_i3strings[i], pixmap, pixmap_gc,
|
draw_text(crash_text_i3strings[i], pixmap, pixmap_gc, NULL,
|
||||||
8, 5 + i * font_height, width - 16);
|
8, 5 + i * font_height, width - 16);
|
||||||
|
|
||||||
/* and reset the colour again for other lines */
|
/* and reset the colour again for other lines */
|
||||||
|
|
4
src/x.c
4
src/x.c
|
@ -552,7 +552,7 @@ void x_draw_decoration(Con *con) {
|
||||||
FREE(formatted_mark);
|
FREE(formatted_mark);
|
||||||
mark_width = predict_text_width(mark);
|
mark_width = predict_text_width(mark);
|
||||||
|
|
||||||
draw_text(mark, parent->pixmap, parent->pm_gc,
|
draw_text(mark, parent->pixmap, parent->pm_gc, NULL,
|
||||||
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);
|
||||||
|
|
||||||
|
@ -561,7 +561,7 @@ 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_text(title,
|
||||||
parent->pixmap, parent->pm_gc,
|
parent->pixmap, parent->pm_gc, NULL,
|
||||||
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)
|
||||||
|
|
Loading…
Reference in New Issue