From 4611bba3dbf63a5ef67bf90d5ebd192eeb07742e Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Thu, 28 Jan 2016 08:39:51 -0500 Subject: [PATCH 01/14] Initial setup of window border rendering Please don't complain to me about the performance of this --- include/render.h | 7 +++++++ sway/CMakeLists.txt | 5 +++++ sway/handlers.c | 6 ++++++ sway/render.c | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 53 insertions(+) create mode 100644 include/render.h create mode 100644 sway/render.c diff --git a/include/render.h b/include/render.h new file mode 100644 index 00000000..19d3a52e --- /dev/null +++ b/include/render.h @@ -0,0 +1,7 @@ +#ifndef _SWAY_RENDER_H +#define _SWAY_RENDER_H +#include + +void render_view_borders(wlc_handle view); + +#endif diff --git a/sway/CMakeLists.txt b/sway/CMakeLists.txt index 5b6104f3..6c62d676 100644 --- a/sway/CMakeLists.txt +++ b/sway/CMakeLists.txt @@ -5,6 +5,8 @@ include_directories( ${JSONC_INCLUDE_DIRS} ${XKBCOMMON_INCLUDE_DIRS} ${LIBINPUT_INCLUDE_DIRS} + ${CAIRO_INCLUDE_DIRS} + ${PANGO_INCLUDE_DIRS} ) add_executable(sway @@ -24,6 +26,7 @@ add_executable(sway output.c resize.c workspace.c + render.c ) add_definitions( @@ -39,6 +42,8 @@ target_link_libraries(sway ${JSONC_LIBRARIES} ${WAYLAND_SERVER_LIBRARIES} ${LIBINPUT_LIBRARIES} + ${PANGO_LIBRARIES} + ${JSONC_LIBRARIES} m ) diff --git a/sway/handlers.c b/sway/handlers.c index 7d4ea263..dff682f5 100644 --- a/sway/handlers.c +++ b/sway/handlers.c @@ -9,6 +9,7 @@ #include #include "handlers.h" +#include "render.h" #include "log.h" #include "layout.h" #include "config.h" @@ -150,6 +151,10 @@ static void handle_output_post_render(wlc_handle output) { ipc_get_pixels(output); } +static void handle_view_pre_render(wlc_handle view) { + render_view_borders(view); +} + static void handle_output_resolution_change(wlc_handle output, const struct wlc_size *from, const struct wlc_size *to) { sway_log(L_DEBUG, "Output %u resolution changed to %d x %d", (unsigned int)output, to->w, to->h); swayc_t *c = swayc_by_handle(output); @@ -716,6 +721,7 @@ void register_wlc_handlers() { wlc_set_view_created_cb(handle_view_created); wlc_set_view_destroyed_cb(handle_view_destroyed); wlc_set_view_focus_cb(handle_view_focus); + wlc_set_view_render_pre_cb(handle_view_pre_render); wlc_set_view_request_geometry_cb(handle_view_geometry_request); wlc_set_view_request_state_cb(handle_view_state_request); wlc_set_keyboard_key_cb(handle_key); diff --git a/sway/render.c b/sway/render.c new file mode 100644 index 00000000..66d2e5f0 --- /dev/null +++ b/sway/render.c @@ -0,0 +1,35 @@ +#include "render.h" +#include +#include + +cairo_t *create_cairo_context(int width, int height, int channels, + cairo_surface_t **surf, unsigned char **buf) { + cairo_t *cr; + *buf = calloc(channels * width * height, sizeof(unsigned char)); + if (!*buf) { + return NULL; + } + *surf = cairo_image_surface_create_for_data(*buf, CAIRO_FORMAT_ARGB32, + width, height, channels * width); + if (cairo_surface_status(*surf) != CAIRO_STATUS_SUCCESS) { + free(*buf); + return NULL; + } + cr = cairo_create(*surf); + if (cairo_status(cr) != CAIRO_STATUS_SUCCESS) { + free(*buf); + return NULL; + } + return cr; +} + +void render_view_borders(wlc_handle view) { + unsigned char *surf_data; + cairo_surface_t *surf; + int texture_id; + const struct wlc_geometry *geo = wlc_view_get_geometry(view); + cairo_t *cr = create_cairo_context(geo->size.w, geo->size.h, 4, &surf, &surf_data); + // TODO + cairo_destroy(cr); + free(surf_data); +} From a8e084433d57609398fd1b72b72d3d7e71925d44 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Thu, 28 Jan 2016 19:41:03 -0500 Subject: [PATCH 02/14] Window borders proof of concept --- sway/render.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/sway/render.c b/sway/render.c index 66d2e5f0..a5ba2f4c 100644 --- a/sway/render.c +++ b/sway/render.c @@ -1,7 +1,16 @@ #include "render.h" -#include +#include +#include #include +void cairo_set_source_u32(cairo_t *cairo, uint32_t color) { + cairo_set_source_rgba(cairo, + (color >> (3*8) & 0xFF) / 255.0, + (color >> (2*8) & 0xFF) / 255.0, + (color >> (1*8) & 0xFF) / 255.0, + (color >> (0*8) & 0xFF) / 255.0); +} + cairo_t *create_cairo_context(int width, int height, int channels, cairo_surface_t **surf, unsigned char **buf) { cairo_t *cr; @@ -24,12 +33,18 @@ cairo_t *create_cairo_context(int width, int height, int channels, } void render_view_borders(wlc_handle view) { + const int bw = 2; unsigned char *surf_data; cairo_surface_t *surf; - int texture_id; - const struct wlc_geometry *geo = wlc_view_get_geometry(view); - cairo_t *cr = create_cairo_context(geo->size.w, geo->size.h, 4, &surf, &surf_data); - // TODO + struct wlc_geometry geo = *wlc_view_get_geometry(view); + cairo_t *cr = create_cairo_context(geo.size.w + bw * 2, geo.size.h + bw * 2, 4, &surf, &surf_data); + cairo_set_source_u32(cr, 0x0000FFFF); + cairo_paint(cr); + geo.origin.x -= bw; + geo.origin.y -= bw; + geo.size.w += bw * 2; + geo.size.h += bw * 2; + wlc_pixels_write(WLC_RGBA8888, &geo, surf_data); cairo_destroy(cr); free(surf_data); } From b903f7f655479b9ed095cf5b5950d963d525dd8c Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sun, 13 Mar 2016 21:10:46 -0400 Subject: [PATCH 03/14] Implement some more on borders Note that this segfaults ALL THE TIME in wlc code. Paging @Cloudef for help, I'm at a loss. --- include/container.h | 15 ++++++ include/render.h | 2 + sway/container.c | 3 ++ sway/handlers.c | 1 + sway/layout.c | 1 + sway/render.c | 111 ++++++++++++++++++++++++++++++++++---------- 6 files changed, 109 insertions(+), 24 deletions(-) diff --git a/include/container.h b/include/container.h index a96beab9..815898d7 100644 --- a/include/container.h +++ b/include/container.h @@ -36,6 +36,12 @@ enum swayc_layouts { L_LAYOUTS, }; +enum swayc_border_types { + B_NONE, /**< No border */ + B_PIXEL, /**< 1px border */ + B_NORMAL /**< Normal border with title bar */ +}; + /** * Stores information about a container. * @@ -109,6 +115,15 @@ struct sway_container { * If this container's children include a fullscreen view, this is that view. */ struct sway_container *fullscreen; + /** + * If this container is a view, this may be set to the window's decoration + * buffer (or NULL). + */ + unsigned char *border; + enum swayc_border_types border_type; + struct wlc_geometry border_geometry; + struct wlc_geometry presumed_geometry; + int border_thickness; }; enum visibility_mask { diff --git a/include/render.h b/include/render.h index 19d3a52e..c3d1ca87 100644 --- a/include/render.h +++ b/include/render.h @@ -1,7 +1,9 @@ #ifndef _SWAY_RENDER_H #define _SWAY_RENDER_H #include +#include "container.h" void render_view_borders(wlc_handle view); +void update_view_border(swayc_t *view); #endif diff --git a/sway/container.c b/sway/container.c index 9330a3de..ac0d3231 100644 --- a/sway/container.c +++ b/sway/container.c @@ -22,8 +22,11 @@ static swayc_t *new_swayc(enum swayc_types type) { c->gaps = -1; c->layout = L_NONE; c->type = type; + c->border_type = B_PIXEL; // TODO: Load default from config + c->border_thickness = 2; if (type != C_VIEW) { c->children = create_list(); + c->border_type = B_NONE; } return c; } diff --git a/sway/handlers.c b/sway/handlers.c index dff682f5..47b649fd 100644 --- a/sway/handlers.c +++ b/sway/handlers.c @@ -357,6 +357,7 @@ static void handle_view_geometry_request(wlc_handle handle, const struct wlc_geo arrange_windows(view->parent, -1, -1); } } + update_view_border(view); } static void handle_view_state_request(wlc_handle view, enum wlc_view_state_bit state, bool toggle) { diff --git a/sway/layout.c b/sway/layout.c index d9c4598f..be898c58 100644 --- a/sway/layout.c +++ b/sway/layout.c @@ -12,6 +12,7 @@ #include "focus.h" #include "output.h" #include "ipc-server.h" +#include "render.h" swayc_t root_container; list_t *scratchpad; diff --git a/sway/render.c b/sway/render.c index a5ba2f4c..9388c1d0 100644 --- a/sway/render.c +++ b/sway/render.c @@ -2,6 +2,8 @@ #include #include #include +#include +#include "container.h" void cairo_set_source_u32(cairo_t *cairo, uint32_t color) { cairo_set_source_rgba(cairo, @@ -11,40 +13,101 @@ void cairo_set_source_u32(cairo_t *cairo, uint32_t color) { (color >> (0*8) & 0xFF) / 255.0); } -cairo_t *create_cairo_context(int width, int height, int channels, - cairo_surface_t **surf, unsigned char **buf) { +cairo_t *create_border_buffer(swayc_t *view, struct wlc_geometry geo, + cairo_surface_t **surface) { + const int channels = 4; cairo_t *cr; - *buf = calloc(channels * width * height, sizeof(unsigned char)); - if (!*buf) { + view->border_geometry = geo; + view->border = calloc(channels * geo.size.w * geo.size.h, + sizeof(unsigned char)); + if (!view->border) { + sway_log(L_DEBUG, "Unable to allocate buffer"); return NULL; } - *surf = cairo_image_surface_create_for_data(*buf, CAIRO_FORMAT_ARGB32, - width, height, channels * width); - if (cairo_surface_status(*surf) != CAIRO_STATUS_SUCCESS) { - free(*buf); + *surface = cairo_image_surface_create_for_data(view->border, + CAIRO_FORMAT_ARGB32, geo.size.w, geo.size.h, channels * geo.size.w); + if (cairo_surface_status(*surface) != CAIRO_STATUS_SUCCESS) { + free(view->border); + view->border = NULL; + sway_log(L_DEBUG, "Unable to allocate surface"); return NULL; } - cr = cairo_create(*surf); + cr = cairo_create(*surface); if (cairo_status(cr) != CAIRO_STATUS_SUCCESS) { - free(*buf); + cairo_surface_destroy(*surface); + free(view->border); + view->border = NULL; + sway_log(L_DEBUG, "Unable to create cairo context"); return NULL; } return cr; } +void update_view_border(swayc_t *view) { + struct wlc_geometry geo; + wlc_view_get_visible_geometry(view->handle, &geo); + cairo_t *cr = NULL; + cairo_surface_t *surface = NULL; + + if (view->border) { + free(view->border); + view->border = NULL; + } + + switch (view->border_type) { + case B_NONE: + view->border_geometry = geo; + break; + case B_PIXEL: + geo.origin.x -= view->border_thickness; + geo.origin.y -= view->border_thickness; + geo.size.w += view->border_thickness * 2; + geo.size.h += view->border_thickness * 2; + if (geo.size.w <= 0 || geo.size.h <= 0) { + view->border = NULL; + break; + } + cr = create_border_buffer(view, geo, &surface); + if (!cr) { + break; + } + cairo_set_source_u32(cr, 0x0000FFFF); + cairo_paint(cr); + break; + case B_NORMAL: + // TODO + break; + } + if (surface) { + cairo_surface_flush(surface); + cairo_surface_destroy(surface); + } + if (cr) { + cairo_destroy(cr); + sway_log(L_DEBUG, "Created border for %p (%dx%d+%d,%d)", view, + geo.size.w, geo.size.h, geo.origin.x, geo.origin.y); + } + view->border_geometry = geo; +} + void render_view_borders(wlc_handle view) { - const int bw = 2; - unsigned char *surf_data; - cairo_surface_t *surf; - struct wlc_geometry geo = *wlc_view_get_geometry(view); - cairo_t *cr = create_cairo_context(geo.size.w + bw * 2, geo.size.h + bw * 2, 4, &surf, &surf_data); - cairo_set_source_u32(cr, 0x0000FFFF); - cairo_paint(cr); - geo.origin.x -= bw; - geo.origin.y -= bw; - geo.size.w += bw * 2; - geo.size.h += bw * 2; - wlc_pixels_write(WLC_RGBA8888, &geo, surf_data); - cairo_destroy(cr); - free(surf_data); + swayc_t *c = swayc_by_handle(view); + if (!c || c->border_type == B_NONE) { + return; + } + struct wlc_geometry geo; + wlc_view_get_visible_geometry(view, &geo); + if (geo.size.w != c->presumed_geometry.size.w + || geo.size.h != c->presumed_geometry.size.h + || geo.origin.x != c->presumed_geometry.origin.x + || geo.origin.y != c->presumed_geometry.origin.y) { + update_view_border(c); + c->presumed_geometry = geo; + } + if (c->border) { + geo = c->border_geometry; + sway_log(L_DEBUG, "Rendering border for %p (%dx%d+%d,%d)", c, + geo.size.w, geo.size.h, geo.origin.x, geo.origin.y); + wlc_pixels_write(WLC_RGBA8888, &c->border_geometry, c->border); + } } From e2774aee3c80088c7509ed31ae00baee92d6c6ba Mon Sep 17 00:00:00 2001 From: Mikkel Oscar Lyderik Date: Mon, 28 Mar 2016 15:16:55 +0200 Subject: [PATCH 04/14] Add default border colors --- include/config.h | 18 ++++++++++++++++++ sway/config.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/include/config.h b/include/config.h index 4bcf55e8..5a58c07c 100644 --- a/include/config.h +++ b/include/config.h @@ -148,6 +148,14 @@ struct bar_config { } colors; }; +struct border_colors { + uint32_t border; + uint32_t background; + uint32_t text; + uint32_t indicator; + uint32_t child_border; +}; + /** * The configuration struct. The result of loading a config file. */ @@ -187,6 +195,16 @@ struct sway_config { list_t *config_chain; const char *current_config; + + // border colors + struct { + struct border_colors focused; + struct border_colors focused_inactive; + struct border_colors unfocused; + struct border_colors urgent; + struct border_colors placeholder; + uint32_t background; + } border_colors; }; /** diff --git a/sway/config.c b/sway/config.c index a877261c..4a1cb2bb 100644 --- a/sway/config.c +++ b/sway/config.c @@ -181,6 +181,39 @@ static void config_defaults(struct sway_config *config) { config->config_chain = create_list(); config->current_config = NULL; + + // border colors + config->border_colors.focused.border = 0x4C7899FF; + config->border_colors.focused.background = 0x285577FF; + config->border_colors.focused.text = 0xFFFFFFFF; + config->border_colors.focused.indicator = 0x2E9EF4FF; + config->border_colors.focused.child_border = 0x285577FF; + + config->border_colors.focused_inactive.border = 0x333333FF; + config->border_colors.focused_inactive.background = 0x5F676AFF; + config->border_colors.focused_inactive.text = 0xFFFFFFFF; + config->border_colors.focused_inactive.indicator = 0x484E50FF; + config->border_colors.focused_inactive.child_border = 0x5F676AFF; + + config->border_colors.unfocused.border = 0x333333FF; + config->border_colors.unfocused.background = 0x222222FF; + config->border_colors.unfocused.text = 0x888888FF; + config->border_colors.unfocused.indicator = 0x292D2EFF; + config->border_colors.unfocused.child_border = 0x222222FF; + + config->border_colors.urgent.border = 0x2F343AFF; + config->border_colors.urgent.background = 0x900000FF; + config->border_colors.urgent.text = 0xFFFFFFFF; + config->border_colors.urgent.indicator = 0x900000FF; + config->border_colors.urgent.child_border = 0x900000FF; + + config->border_colors.placeholder.border = 0x000000FF; + config->border_colors.placeholder.background = 0x0C0C0CFF; + config->border_colors.placeholder.text = 0xFFFFFFFF; + config->border_colors.placeholder.indicator = 0x000000FF; + config->border_colors.placeholder.child_border = 0x0C0C0CFF; + + config->border_colors.background = 0xFFFFFFFF; } static int compare_modifiers(const void *left, const void *right) { From da567317ab27ec033fa53c6e4b4823dcfce7d24d Mon Sep 17 00:00:00 2001 From: Mikkel Oscar Lyderik Date: Mon, 28 Mar 2016 19:38:19 +0200 Subject: [PATCH 05/14] Make pango: prefix optional for font config --- sway/commands.c | 12 ++++++------ sway/config.c | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/sway/commands.c b/sway/commands.c index 4d0da26e..333af1b4 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -1872,16 +1872,16 @@ static struct cmd_results *cmd_font(int argc, char **argv) { } char *font = join_args(argv, argc); + free(config->font); if (strlen(font) > 6 && strncmp("pango:", font, 6) == 0) { - free(config->font); - config->font = font; - sway_log(L_DEBUG, "Settings font %s", config->font); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); - } else { + config->font = strdup(font + 6); free(font); - return cmd_results_new(CMD_FAILURE, "font", "non-pango font detected"); + } else { + config->font = font; } + sway_log(L_DEBUG, "Settings font %s", config->font); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/config.c b/sway/config.c index 4a1cb2bb..4cb8cced 100644 --- a/sway/config.c +++ b/sway/config.c @@ -160,7 +160,7 @@ static void config_defaults(struct sway_config *config) { config->resizing_key = M_RIGHT_CLICK; config->default_layout = L_NONE; config->default_orientation = L_NONE; - config->font = strdup("pango:monospace 10"); + config->font = strdup("monospace 10"); // Flags config->focus_follows_mouse = true; From cefcce48aad4e452be9d081b1cd1521e2b042e97 Mon Sep 17 00:00:00 2001 From: Mikkel Oscar Lyderik Date: Mon, 28 Mar 2016 22:22:46 +0200 Subject: [PATCH 06/14] Make client/pango.h not depend on client/window.h --- include/client/pango.h | 10 +++++----- swaybar/render.c | 22 +++++++++++----------- wayland/pango.c | 22 ++++++++++------------ 3 files changed, 26 insertions(+), 28 deletions(-) diff --git a/include/client/pango.h b/include/client/pango.h index e25a2211..97c31e38 100644 --- a/include/client/pango.h +++ b/include/client/pango.h @@ -1,12 +1,12 @@ #ifndef _SWAY_CLIENT_PANGO_H #define _SWAY_CLIENT_PANGO_H -#include "client/window.h" -#include "client/buffer.h" +#include +#include #include -PangoLayout *get_pango_layout(struct window *window, struct buffer *buffer, const char *text); -void get_text_size(struct window *window, int *width, int *height, const char *fmt, ...); -void pango_printf(struct window *window, const char *fmt, ...); +PangoLayout *get_pango_layout(cairo_t *cairo, const char *font, const char *text); +void get_text_size(cairo_t *cairo, const char *font, int *width, int *height, const char *fmt, ...); +void pango_printf(cairo_t *cairo, const char *font, const char *fmt, ...); #endif diff --git a/swaybar/render.c b/swaybar/render.c index 1573a373..fff47ab0 100644 --- a/swaybar/render.c +++ b/swaybar/render.c @@ -50,7 +50,7 @@ static void render_sharp_line(cairo_t *cairo, uint32_t color, double x, double y static void render_block(struct window *window, struct config *config, struct status_block *block, double *x, bool edge) { int width, height, sep_width; - get_text_size(window, &width, &height, "%s", block->full_text); + get_text_size(window->cairo, window->font, &width, &height, "%s", block->full_text); int textwidth = width; double block_width = width; @@ -74,7 +74,7 @@ static void render_block(struct window *window, struct config *config, struct st // Add separator if (!edge) { if (config->sep_symbol) { - get_text_size(window, &sep_width, &height, "%s", config->sep_symbol); + get_text_size(window->cairo, window->font, &sep_width, &height, "%s", config->sep_symbol); if (sep_width > block->separator_block_width) { block->separator_block_width = sep_width + margin * 2; } @@ -136,7 +136,7 @@ static void render_block(struct window *window, struct config *config, struct st cairo_move_to(window->cairo, offset, margin); cairo_set_source_u32(window->cairo, block->color); - pango_printf(window, "%s", block->full_text); + pango_printf(window->cairo, window->font, "%s", block->full_text); pos += width; @@ -159,7 +159,7 @@ static void render_block(struct window *window, struct config *config, struct st if (config->sep_symbol) { offset = pos + (block->separator_block_width - sep_width) / 2; cairo_move_to(window->cairo, offset, margin); - pango_printf(window, "%s", config->sep_symbol); + pango_printf(window->cairo, window->font, "%s", config->sep_symbol); } else { cairo_set_line_width(window->cairo, 1); cairo_move_to(window->cairo, pos + block->separator_block_width/2, @@ -201,7 +201,7 @@ static void render_workspace_button(struct window *window, struct config *config char *name = handle_workspace_number(config->strip_workspace_numbers, ws->name); int width, height; - get_text_size(window, &width, &height, "%s", name); + get_text_size(window->cairo, window->font, &width, &height, "%s", name); struct box_colors box_colors; if (ws->urgent) { box_colors = config->colors.urgent_workspace; @@ -228,7 +228,7 @@ static void render_workspace_button(struct window *window, struct config *config // text cairo_set_source_u32(window->cairo, box_colors.text); cairo_move_to(window->cairo, (int)*x + ws_horizontal_padding, margin); - pango_printf(window, "%s", name); + pango_printf(window->cairo, window->font, "%s", name); *x += width + ws_horizontal_padding * 2 + ws_spacing; @@ -237,7 +237,7 @@ static void render_workspace_button(struct window *window, struct config *config static void render_binding_mode_indicator(struct window *window, struct config *config, double pos) { int width, height; - get_text_size(window, &width, &height, "%s", config->mode); + get_text_size(window->cairo, window->font, &width, &height, "%s", config->mode); // background cairo_set_source_u32(window->cairo, config->colors.binding_mode.background); @@ -254,7 +254,7 @@ static void render_binding_mode_indicator(struct window *window, struct config * // text cairo_set_source_u32(window->cairo, config->colors.binding_mode.text); cairo_move_to(window->cairo, (int)pos + ws_horizontal_padding, margin); - pango_printf(window, "%s", config->mode); + pango_printf(window->cairo, window->font, "%s", config->mode); } void render(struct output *output, struct config *config, struct status_line *line) { @@ -278,9 +278,9 @@ void render(struct output *output, struct config *config, struct status_line *li int width, height; if (line->protocol == TEXT) { - get_text_size(window, &width, &height, "%s", line->text_line); + get_text_size(window->cairo, window->font, &width, &height, "%s", line->text_line); cairo_move_to(cairo, window->width - margin - width, margin); - pango_printf(window, "%s", line->text_line); + pango_printf(window->cairo, window->font, "%s", line->text_line); } else if (line->protocol == I3BAR && line->block_line) { double pos = window->width - 0.5; bool edge = true; @@ -312,7 +312,7 @@ void render(struct output *output, struct config *config, struct status_line *li void set_window_height(struct window *window, int height) { int text_width, text_height; - get_text_size(window, &text_width, &text_height, "Test string for measuring purposes"); + get_text_size(window->cairo, window->font, &text_width, &text_height, "Test string for measuring purposes"); if (height > 0) { margin = (height - text_height) / 2; ws_vertical_padding = margin - 1.5; diff --git a/wayland/pango.c b/wayland/pango.c index 9766be6a..d79d89b3 100644 --- a/wayland/pango.c +++ b/wayland/pango.c @@ -4,21 +4,19 @@ #include #include #include -#include "client/window.h" -#include "client/buffer.h" #include "log.h" -PangoLayout *get_pango_layout(struct window *window, const char *text) { - PangoLayout *layout = pango_cairo_create_layout(window->cairo); +PangoLayout *get_pango_layout(cairo_t *cairo, const char *font, const char *text) { + PangoLayout *layout = pango_cairo_create_layout(cairo); pango_layout_set_text(layout, text, -1); - PangoFontDescription *desc = pango_font_description_from_string(window->font); + PangoFontDescription *desc = pango_font_description_from_string(font); pango_layout_set_font_description(layout, desc); pango_layout_set_single_paragraph_mode(layout, 1); pango_font_description_free(desc); return layout; } -void get_text_size(struct window *window, int *width, int *height, const char *fmt, ...) { +void get_text_size(cairo_t *cairo, const char *font, int *width, int *height, const char *fmt, ...) { char *buf = malloc(2048); va_list args; @@ -28,8 +26,8 @@ void get_text_size(struct window *window, int *width, int *height, const char *f } va_end(args); - PangoLayout *layout = get_pango_layout(window, buf); - pango_cairo_update_layout(window->cairo, layout); + PangoLayout *layout = get_pango_layout(cairo, font, buf); + pango_cairo_update_layout(cairo, layout); pango_layout_get_pixel_size(layout, width, height); @@ -38,7 +36,7 @@ void get_text_size(struct window *window, int *width, int *height, const char *f free(buf); } -void pango_printf(struct window *window, const char *fmt, ...) { +void pango_printf(cairo_t *cairo, const char *font, const char *fmt, ...) { char *buf = malloc(2048); va_list args; @@ -48,10 +46,10 @@ void pango_printf(struct window *window, const char *fmt, ...) { } va_end(args); - PangoLayout *layout = get_pango_layout(window, buf); - pango_cairo_update_layout(window->cairo, layout); + PangoLayout *layout = get_pango_layout(cairo, font, buf); + pango_cairo_update_layout(cairo, layout); - pango_cairo_show_layout(window->cairo, layout); + pango_cairo_show_layout(cairo, layout); g_object_unref(layout); From 86ea79ea6de62c0958511d45e755a4a7767efcd0 Mon Sep 17 00:00:00 2001 From: Mikkel Oscar Lyderik Date: Tue, 29 Mar 2016 13:49:28 +0200 Subject: [PATCH 07/14] Implement parsing of hide_edge_borders --- include/config.h | 9 +++++++++ sway/commands.c | 25 +++++++++++++++++++++++++ sway/config.c | 2 ++ sway/sway.5.txt | 3 +++ 4 files changed, 39 insertions(+) diff --git a/include/config.h b/include/config.h index 5a58c07c..fe69e310 100644 --- a/include/config.h +++ b/include/config.h @@ -156,6 +156,13 @@ struct border_colors { uint32_t child_border; }; +enum edge_border_types { + E_NONE, /**< Don't hide edge borders */ + E_VERTICAL, /**< hide vertical edge borders */ + E_HORIZONTAL, /**< hide horizontal edge borders */ + E_BOTH /**< hide vertical and horizontal edge borders */ +}; + /** * The configuration struct. The result of loading a config file. */ @@ -196,6 +203,8 @@ struct sway_config { list_t *config_chain; const char *current_config; + enum edge_border_types hide_edge_borders; + // border colors struct { struct border_colors focused; diff --git a/sway/commands.c b/sway/commands.c index 333af1b4..4a3ebf9e 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -55,6 +55,7 @@ static sway_cmd cmd_font; static sway_cmd cmd_for_window; static sway_cmd cmd_fullscreen; static sway_cmd cmd_gaps; +static sway_cmd cmd_hide_edge_borders; static sway_cmd cmd_include; static sway_cmd cmd_input; static sway_cmd cmd_kill; @@ -1506,6 +1507,29 @@ static struct cmd_results *cmd_smart_gaps(int argc, char **argv) { return cmd_results_new(CMD_SUCCESS, NULL, NULL); } +static struct cmd_results *cmd_hide_edge_borders(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "hide_edge_borders", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + if (strcasecmp(argv[0], "none") == 0) { + config->hide_edge_borders = E_NONE; + } else if (strcasecmp(argv[0], "vertical") == 0) { + config->hide_edge_borders = E_VERTICAL; + } else if (strcasecmp(argv[0], "horizontal") == 0) { + config->hide_edge_borders = E_HORIZONTAL; + } else if (strcasecmp(argv[0], "both") == 0) { + config->hide_edge_borders = E_BOTH; + } else { + return cmd_results_new(CMD_INVALID, "hide_edge_borders", + "Expected 'hide_edge_borders '"); + } + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + + static struct cmd_results *cmd_kill(int argc, char **argv) { if (config->reading) return cmd_results_new(CMD_FAILURE, "kill", "Can't be used in config file."); if (!config->active) return cmd_results_new(CMD_FAILURE, "kill", "Can only be used when sway is running."); @@ -2063,6 +2087,7 @@ static struct cmd_handler handlers[] = { { "for_window", cmd_for_window }, { "fullscreen", cmd_fullscreen }, { "gaps", cmd_gaps }, + { "hide_edge_borders", cmd_hide_edge_borders }, { "include", cmd_include }, { "input", cmd_input }, { "kill", cmd_kill }, diff --git a/sway/config.c b/sway/config.c index 4cb8cced..565acd05 100644 --- a/sway/config.c +++ b/sway/config.c @@ -182,6 +182,8 @@ static void config_defaults(struct sway_config *config) { config->config_chain = create_list(); config->current_config = NULL; + config->hide_edge_borders = E_NONE; + // border colors config->border_colors.focused.border = 0x4C7899FF; config->border_colors.focused.background = 0x285577FF; diff --git a/sway/sway.5.txt b/sway/sway.5.txt index 1bb5cd3b..13d304bb 100644 --- a/sway/sway.5.txt +++ b/sway/sway.5.txt @@ -67,6 +67,9 @@ They are expected to be used with **bindsym** or at runtime through **swaymsg**( **fullscreen**:: Toggles fullscreen status for the focused view. +**hide_edge_borders** :: + Hide window borders adjacent to the screen edges. Default is _none_. + **layout** :: Sets the layout mode of the focused container. _mode_ can be one of _splith_, _splitv_, or _toggle split_. From 3b05f92f76c3bd9400320844e485eb06e94772cd Mon Sep 17 00:00:00 2001 From: Mikkel Oscar Lyderik Date: Tue, 29 Mar 2016 14:40:25 +0200 Subject: [PATCH 08/14] Add border config --- include/config.h | 2 ++ include/container.h | 8 +++---- sway/commands.c | 51 +++++++++++++++++++++++++++++++++++++++++++++ sway/config.c | 3 +++ sway/sway.5.txt | 9 ++++++++ 5 files changed, 69 insertions(+), 4 deletions(-) diff --git a/include/config.h b/include/config.h index fe69e310..a35cfd0a 100644 --- a/include/config.h +++ b/include/config.h @@ -203,6 +203,8 @@ struct sway_config { list_t *config_chain; const char *current_config; + enum swayc_border_types border; + int border_thickness; enum edge_border_types hide_edge_borders; // border colors diff --git a/include/container.h b/include/container.h index 815898d7..07514c8a 100644 --- a/include/container.h +++ b/include/container.h @@ -8,7 +8,7 @@ typedef struct sway_container swayc_t; /** * Different kinds of containers. - * + * * This enum is in order. A container will never be inside of a container below * it on this list. */ @@ -37,9 +37,9 @@ enum swayc_layouts { }; enum swayc_border_types { - B_NONE, /**< No border */ - B_PIXEL, /**< 1px border */ - B_NORMAL /**< Normal border with title bar */ + B_NONE, /**< No border */ + B_PIXEL, /**< 1px border */ + B_NORMAL /**< Normal border with title bar */ }; /** diff --git a/sway/commands.c b/sway/commands.c index 4a3ebf9e..bc182cee 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -43,6 +43,7 @@ static sway_cmd cmd_assign; static sway_cmd cmd_bar; static sway_cmd cmd_bindcode; static sway_cmd cmd_bindsym; +static sway_cmd cmd_border; static sway_cmd cmd_debuglog; static sway_cmd cmd_exec; static sway_cmd cmd_exec_always; @@ -346,6 +347,55 @@ static struct cmd_results *cmd_bindcode(int argc, char **argv) { return cmd_results_new(CMD_SUCCESS, NULL, NULL); } +static struct cmd_results *cmd_border(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "border", EXPECTED_AT_LEAST, 1))) { + return error; + } + + if (argc > 2) { + return cmd_results_new(CMD_FAILURE, "border", + "Expected 'border []"); + } + + enum swayc_border_types border = config->border; + + if (strcasecmp(argv[0], "none") == 0) { + border = B_NONE; + } else if (strcasecmp(argv[0], "normal") == 0) { + border = B_NORMAL; + } else if (strcasecmp(argv[0], "pixel") == 0) { + border = B_PIXEL; + } else if (strcasecmp(argv[0], "toggle") == 0) { + switch (config->border) { + case B_NONE: + border = B_PIXEL; + break; + case B_NORMAL: + border = B_NONE; + break; + case B_PIXEL: + border = B_NORMAL; + break; + } + } else { + return cmd_results_new(CMD_FAILURE, "border", + "Expected 'border "); + } + + if (argc == 2 && (border == B_NORMAL || border == B_PIXEL)) { + int thickness = (int)strtol(argv[1], NULL, 10); + if (errno == ERANGE || thickness < 0) { + errno = 0; + return cmd_results_new(CMD_INVALID, "border", "Number is out out of range."); + } + config->border_thickness = thickness; + } + + config->border = border; + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + static struct cmd_results *cmd_exec_always(int argc, char **argv) { struct cmd_results *error = NULL; if (!config->active) return cmd_results_new(CMD_DEFER, NULL, NULL); @@ -2074,6 +2124,7 @@ static struct cmd_handler handlers[] = { { "bar", cmd_bar }, { "bindcode", cmd_bindcode }, { "bindsym", cmd_bindsym }, + { "border", cmd_border }, { "debuglog", cmd_debuglog }, { "default_orientation", cmd_orientation }, { "exec", cmd_exec }, diff --git a/sway/config.c b/sway/config.c index 565acd05..193cfad2 100644 --- a/sway/config.c +++ b/sway/config.c @@ -182,6 +182,9 @@ static void config_defaults(struct sway_config *config) { config->config_chain = create_list(); config->current_config = NULL; + // borders + config->border = B_NORMAL; + config->border_thickness = 2; config->hide_edge_borders = E_NONE; // border colors diff --git a/sway/sway.5.txt b/sway/sway.5.txt index 13d304bb..2eb0276c 100644 --- a/sway/sway.5.txt +++ b/sway/sway.5.txt @@ -43,6 +43,15 @@ The following commands may only be used in the configuration file. The following commands cannot be used directly in the configuration file. They are expected to be used with **bindsym** or at runtime through **swaymsg**(1). +**border** []:: + Set border style for windows. _normal_ includes a border of thickness _n_ and + a title bar. _pixel_ is just the border without title bar. Default is _normal_ + with border thickness 2. + +**border** :: + Set border style to _none_ or _toggle_ between the available border styles: + _normal_, _pixel_, _none_. + **exit**:: Exit sway and end your Wayland session. From 5a13cb0ed136906a4370235214601b0129548c49 Mon Sep 17 00:00:00 2001 From: Mikkel Oscar Lyderik Date: Tue, 29 Mar 2016 14:47:30 +0200 Subject: [PATCH 09/14] Implement borders The borders are implemented as a surface/buffer attached to each view which is sent to and rendered by wlc in the view_pre_render callback. All the drawing logic is handled in sway/border.c and all the logic for calculating the geometry of the border/view is handled in `update_geometry` in sway/layout.c (same place as gaps are calculated). --- include/{render.h => border.h} | 5 +- include/config.h | 1 + include/container.h | 17 +-- sway/CMakeLists.txt | 3 +- sway/border.c | 247 +++++++++++++++++++++++++++++++++ sway/commands.c | 29 +++- sway/config.c | 2 + sway/container.c | 22 +-- sway/focus.c | 3 + sway/handlers.c | 17 ++- sway/layout.c | 76 +++++++++- sway/render.c | 113 --------------- 12 files changed, 386 insertions(+), 149 deletions(-) rename include/{render.h => border.h} (60%) create mode 100644 sway/border.c delete mode 100644 sway/render.c diff --git a/include/render.h b/include/border.h similarity index 60% rename from include/render.h rename to include/border.h index c3d1ca87..63cd63d2 100644 --- a/include/render.h +++ b/include/border.h @@ -1,9 +1,10 @@ -#ifndef _SWAY_RENDER_H -#define _SWAY_RENDER_H +#ifndef _SWAY_BORDER_H +#define _SWAY_BORDER_H #include #include "container.h" void render_view_borders(wlc_handle view); void update_view_border(swayc_t *view); +int get_font_text_height(const char *font); #endif diff --git a/include/config.h b/include/config.h index a35cfd0a..fb84423c 100644 --- a/include/config.h +++ b/include/config.h @@ -184,6 +184,7 @@ struct sway_config { enum swayc_layouts default_orientation; enum swayc_layouts default_layout; char *font; + int font_height; // Flags bool focus_follows_mouse; diff --git a/include/container.h b/include/container.h index 07514c8a..26da851e 100644 --- a/include/container.h +++ b/include/container.h @@ -115,15 +115,16 @@ struct sway_container { * If this container's children include a fullscreen view, this is that view. */ struct sway_container *fullscreen; - /** - * If this container is a view, this may be set to the window's decoration - * buffer (or NULL). - */ - unsigned char *border; - enum swayc_border_types border_type; + /** + * If this container is a view, this may be set to the window's decoration + * buffer (or NULL). + */ + unsigned char *border; + enum swayc_border_types border_type; struct wlc_geometry border_geometry; - struct wlc_geometry presumed_geometry; - int border_thickness; + struct wlc_geometry title_bar_geometry; + struct wlc_geometry actual_geometry; + int border_thickness; }; enum visibility_mask { diff --git a/sway/CMakeLists.txt b/sway/CMakeLists.txt index 6c62d676..51f27a05 100644 --- a/sway/CMakeLists.txt +++ b/sway/CMakeLists.txt @@ -26,7 +26,7 @@ add_executable(sway output.c resize.c workspace.c - render.c + border.c ) add_definitions( @@ -36,6 +36,7 @@ add_definitions( target_link_libraries(sway sway-common sway-protocols + sway-wayland ${WLC_LIBRARIES} ${XKBCOMMON_LIBRARIES} ${PCRE_LIBRARIES} diff --git a/sway/border.c b/sway/border.c new file mode 100644 index 00000000..8c9106e4 --- /dev/null +++ b/sway/border.c @@ -0,0 +1,247 @@ +#include "border.h" +#include +#include +#include +#include +#include +#include "container.h" +#include "config.h" +#include "client/pango.h" + +void cairo_set_source_u32(cairo_t *cairo, uint32_t color) { + int endian = 1; + if (*(char *)&endian == 1) { + cairo_set_source_rgba(cairo, + (color >> (1*8) & 0xFF) / 255.0, + (color >> (2*8) & 0xFF) / 255.0, + (color >> (3*8) & 0xFF) / 255.0, + (color >> (0*8) & 0xFF) / 255.0); + } else { + cairo_set_source_rgba(cairo, + (color >> (0*8) & 0xFF) / 255.0, + (color >> (3*8) & 0xFF) / 255.0, + (color >> (2*8) & 0xFF) / 255.0, + (color >> (1*8) & 0xFF) / 255.0); + } +} + +static cairo_t *create_border_buffer(swayc_t *view, struct wlc_geometry geo, cairo_surface_t **surface) { + cairo_t *cr; + view->border_geometry = geo; + int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, geo.size.w); + view->border = calloc(stride * geo.size.h, sizeof(unsigned char)); + if (!view->border) { + sway_log(L_DEBUG, "Unable to allocate buffer"); + return NULL; + } + *surface = cairo_image_surface_create_for_data(view->border, + CAIRO_FORMAT_ARGB32, geo.size.w, geo.size.h, stride); + if (cairo_surface_status(*surface) != CAIRO_STATUS_SUCCESS) { + free(view->border); + view->border = NULL; + sway_log(L_DEBUG, "Unable to allocate surface"); + return NULL; + } + cr = cairo_create(*surface); + if (cairo_status(cr) != CAIRO_STATUS_SUCCESS) { + cairo_surface_destroy(*surface); + free(view->border); + view->border = NULL; + sway_log(L_DEBUG, "Unable to create cairo context"); + return NULL; + } + return cr; +} + +// TODO: move to client/cairo.h when local set_source_u32 is fixed. +/** + * Renders a sharp line of any width and height. + * + * The line is drawn from (x,y) to (x+width,y+height) where width/height is 0 + * if the line has a width/height of one pixel, respectively. + */ +static void render_sharp_line(cairo_t *cairo, uint32_t color, double x, double y, double width, double height) { + cairo_set_source_u32(cairo, color); + + if (width > 1 && height > 1) { + cairo_rectangle(cairo, x, y, width, height); + cairo_fill(cairo); + } else { + if (width == 1) { + x += 0.5; + height += y; + width = x; + } + + if (height == 1) { + y += 0.5; + width += x; + height = y; + } + + cairo_move_to(cairo, x, y); + cairo_set_line_width(cairo, 1.0); + cairo_line_to(cairo, width, height); + cairo_stroke(cairo); + } +} + +int get_font_text_height(const char *font) { + cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 200, 200); + cairo_t *cr = cairo_create(surface); + int width, height; + get_text_size(cr, font, &width, &height, "Gg"); + return height; +} + +static void render_borders(swayc_t *view, cairo_t *cr, struct border_colors *colors) { + struct wlc_geometry *b = &view->border_geometry; + struct wlc_geometry *v = &view->actual_geometry; + + // left border + int left_border = v->origin.x - b->origin.x; + if (left_border > 0) { + render_sharp_line(cr, + colors->child_border, + 0, 0, + left_border, + b->size.h); + } + + // right border + int right_border = b->size.w - v->size.w - left_border; + if (right_border > 0) { + render_sharp_line(cr, + colors->child_border, + b->size.w - right_border, + 0, + right_border, + b->size.h); + } + + // top border + int top_border = v->origin.y - b->origin.y; + if (top_border > 0) { + render_sharp_line(cr, + colors->child_border, + 0, 0, + b->size.w, + top_border); + } + + // bottom border + int bottom_border = b->size.h - (top_border + v->size.h); + if (bottom_border > 0) { + render_sharp_line(cr, + colors->child_border, + 0, + b->size.h - bottom_border, + b->size.w, + bottom_border); + } +} + +static void render_with_title_bar(swayc_t *view, cairo_t *cr, struct border_colors *colors) { + struct wlc_geometry *tb = &view->title_bar_geometry; + struct wlc_geometry *b = &view->border_geometry; + + // borders + render_borders(view, cr, colors); + + // title bar background + cairo_set_source_u32(cr, colors->child_border); + cairo_rectangle(cr, 0, 0, tb->size.w, tb->size.h); + cairo_fill(cr); + + // header top line + render_sharp_line(cr, colors->border, 0, 0, tb->size.w, 1); + + // text + int width, height; + get_text_size(cr, config->font, &width, &height, "%s", view->name); + cairo_move_to(cr, view->border_thickness, 2); + cairo_set_source_u32(cr, colors->text); + pango_printf(cr, config->font, "%s", view->name); + + // header bottom line + render_sharp_line(cr, colors->border, + view->actual_geometry.origin.x - b->origin.x, + tb->size.h - 1, + view->actual_geometry.size.w, 1); +} + +void update_view_border(swayc_t *view) { + cairo_t *cr = NULL; + cairo_surface_t *surface = NULL; + + if (view->border) { + free(view->border); + view->border = NULL; + } + + swayc_t *focused = get_focused_view(&root_container); + swayc_t *container = swayc_parent_by_type(view, C_CONTAINER); + swayc_t *focused_inactive = NULL; + if (container) { + focused_inactive = swayc_focus_by_type(container, C_VIEW); + } else { + container = swayc_parent_by_type(view, C_WORKSPACE); + if (container) { + focused_inactive = swayc_focus_by_type(container, C_VIEW); + } + } + + switch (view->border_type) { + case B_NONE: + break; + case B_PIXEL: + cr = create_border_buffer(view, view->border_geometry, &surface); + if (!cr) { + break; + } + + if (focused == view) { + render_borders(view, cr, &config->border_colors.focused); + } else if (focused_inactive == view) { + render_borders(view, cr, &config->border_colors.focused_inactive); + } else { + render_borders(view, cr, &config->border_colors.unfocused); + } + + break; + case B_NORMAL: + cr = create_border_buffer(view, view->border_geometry, &surface); + if (!cr) { + break; + } + + if (focused == view) { + render_with_title_bar(view, cr, &config->border_colors.focused); + } else if (focused_inactive == view) { + render_with_title_bar(view, cr, &config->border_colors.focused_inactive); + } else { + render_with_title_bar(view, cr, &config->border_colors.unfocused); + } + + break; + } + if (surface) { + cairo_surface_flush(surface); + cairo_surface_destroy(surface); + } + if (cr) { + cairo_destroy(cr); + } +} + +void render_view_borders(wlc_handle view) { + swayc_t *c = swayc_by_handle(view); + + if (!c || c->border_type == B_NONE) { + return; + } + + if (c->border) { + wlc_pixels_write(WLC_RGBA8888, &c->border_geometry, c->border); + } +} diff --git a/sway/commands.c b/sway/commands.c index bc182cee..c53b13c3 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -31,6 +31,7 @@ #include "ipc-server.h" #include "list.h" #include "input.h" +#include "border.h" typedef struct cmd_results *sway_cmd(int argc, char **argv); @@ -359,6 +360,14 @@ static struct cmd_results *cmd_border(int argc, char **argv) { } enum swayc_border_types border = config->border; + int thickness = config->border_thickness; + + swayc_t *view = NULL; + if (config->active) { + view = get_focused_view(&root_container); + border = view->border_type; + thickness = view->border_thickness; + } if (strcasecmp(argv[0], "none") == 0) { border = B_NONE; @@ -367,7 +376,7 @@ static struct cmd_results *cmd_border(int argc, char **argv) { } else if (strcasecmp(argv[0], "pixel") == 0) { border = B_PIXEL; } else if (strcasecmp(argv[0], "toggle") == 0) { - switch (config->border) { + switch (border) { case B_NONE: border = B_PIXEL; break; @@ -383,16 +392,24 @@ static struct cmd_results *cmd_border(int argc, char **argv) { "Expected 'border "); } + if (argc == 2 && (border == B_NORMAL || border == B_PIXEL)) { - int thickness = (int)strtol(argv[1], NULL, 10); + thickness = (int)strtol(argv[1], NULL, 10); if (errno == ERANGE || thickness < 0) { errno = 0; return cmd_results_new(CMD_INVALID, "border", "Number is out out of range."); } + } + + if (config->active && view) { + view->border_type = border; + view->border_thickness = thickness; + update_geometry(view); + } else { + config->border = border; config->border_thickness = thickness; } - config->border = border; return cmd_results_new(CMD_SUCCESS, NULL, NULL); } @@ -904,9 +921,9 @@ static struct cmd_results *cmd_move(int argc, char **argv) { } else if (strcasecmp(argv[0], "position") == 0 && strcasecmp(argv[1], "mouse") == 0) { if (view->is_floating) { swayc_t *output = swayc_parent_by_type(view, C_OUTPUT); - const struct wlc_geometry *geometry = wlc_view_get_geometry(view->handle); + struct wlc_geometry g; + wlc_view_get_visible_geometry(view->handle, &g); const struct wlc_size *size = wlc_output_get_resolution(output->handle); - struct wlc_geometry g = *geometry; struct wlc_point origin; wlc_pointer_get_position(&origin); @@ -1954,6 +1971,8 @@ static struct cmd_results *cmd_font(int argc, char **argv) { config->font = font; } + config->font_height = get_font_text_height(config->font); + sway_log(L_DEBUG, "Settings font %s", config->font); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/config.c b/sway/config.c index 193cfad2..5501ab31 100644 --- a/sway/config.c +++ b/sway/config.c @@ -22,6 +22,7 @@ #include "input_state.h" #include "criteria.h" #include "input.h" +#include "border.h" struct sway_config *config = NULL; @@ -161,6 +162,7 @@ static void config_defaults(struct sway_config *config) { config->default_layout = L_NONE; config->default_orientation = L_NONE; config->font = strdup("monospace 10"); + config->font_height = get_font_text_height(config->font); // Flags config->focus_follows_mouse = true; diff --git a/sway/container.c b/sway/container.c index ac0d3231..21a929b9 100644 --- a/sway/container.c +++ b/sway/container.c @@ -22,8 +22,8 @@ static swayc_t *new_swayc(enum swayc_types type) { c->gaps = -1; c->layout = L_NONE; c->type = type; - c->border_type = B_PIXEL; // TODO: Load default from config - c->border_thickness = 2; + c->border_type = config->border; + c->border_thickness = config->border_thickness; if (type != C_VIEW) { c->children = create_list(); c->border_type = B_NONE; @@ -269,11 +269,12 @@ swayc_t *new_view(swayc_t *sibling, wlc_handle handle) { view->is_focused = true; view->sticky = false; // Setup geometry - const struct wlc_geometry* geometry = wlc_view_get_geometry(handle); + struct wlc_geometry geometry; + wlc_view_get_visible_geometry(handle, &geometry); view->width = 0; view->height = 0; - view->desired_width = geometry->size.w; - view->desired_height = geometry->size.h; + view->desired_width = geometry.size.w; + view->desired_height = geometry.size.h; view->is_floating = false; @@ -306,13 +307,14 @@ swayc_t *new_floating_view(wlc_handle handle) { view->sticky = false; // Set the geometry of the floating view - const struct wlc_geometry* geometry = wlc_view_get_geometry(handle); + struct wlc_geometry geometry; + wlc_view_get_visible_geometry(handle, &geometry); // give it requested geometry, but place in center - view->x = (swayc_active_workspace()->width - geometry->size.w) / 2; - view->y = (swayc_active_workspace()->height- geometry->size.h) / 2; - view->width = geometry->size.w; - view->height = geometry->size.h; + view->x = (swayc_active_workspace()->width - geometry.size.w) / 2; + view->y = (swayc_active_workspace()->height- geometry.size.h) / 2; + view->width = geometry.size.w; + view->height = geometry.size.h; view->desired_width = view->width; view->desired_height = view->height; diff --git a/sway/focus.c b/sway/focus.c index 7f96eda7..4cae3b47 100644 --- a/sway/focus.c +++ b/sway/focus.c @@ -7,6 +7,7 @@ #include "config.h" #include "input_state.h" #include "ipc-server.h" +#include "border.h" bool locked_container_focus = false; bool locked_view_focus = false; @@ -130,6 +131,7 @@ bool set_focused_container(swayc_t *c) { // unactivate previous focus if (focused->type == C_VIEW) { wlc_view_set_state(focused->handle, WLC_BIT_ACTIVATED, false); + update_view_border(focused); } // activate current focus if (p->type == C_VIEW) { @@ -137,6 +139,7 @@ bool set_focused_container(swayc_t *c) { // set focus if view_focus is unlocked if (!locked_view_focus) { wlc_view_focus(p->handle); + update_view_border(p); } } } else if (p->type == C_WORKSPACE) { diff --git a/sway/handlers.c b/sway/handlers.c index 47b649fd..fc473640 100644 --- a/sway/handlers.c +++ b/sway/handlers.c @@ -9,7 +9,7 @@ #include #include "handlers.h" -#include "render.h" +#include "border.h" #include "log.h" #include "layout.h" #include "config.h" @@ -349,15 +349,14 @@ static void handle_view_geometry_request(wlc_handle handle, const struct wlc_geo view->desired_width = geometry->size.w; view->desired_height = geometry->size.h; - if (view->is_floating) { - view->width = view->desired_width; - view->height = view->desired_height; - view->x = geometry->origin.x; - view->y = geometry->origin.y; - arrange_windows(view->parent, -1, -1); - } + /* if (view->is_floating) { */ + /* view->width = view->desired_width; */ + /* view->height = view->desired_height; */ + /* view->x = geometry->origin.x; */ + /* view->y = geometry->origin.y; */ + /* /1* arrange_windows(view->parent, -1, -1); *1/ */ + /* } */ } - update_view_border(view); } static void handle_view_state_request(wlc_handle view, enum wlc_view_state_bit state, bool toggle) { diff --git a/sway/layout.c b/sway/layout.c index be898c58..a282f36e 100644 --- a/sway/layout.c +++ b/sway/layout.c @@ -12,7 +12,7 @@ #include "focus.h" #include "output.h" #include "ipc-server.h" -#include "render.h" +#include "border.h" swayc_t root_container; list_t *scratchpad; @@ -427,6 +427,80 @@ void update_geometry(swayc_t *container) { geometry.size.h = ws->y + ws->height - geometry.origin.y; } } + + if (swayc_is_fullscreen(container)) { + container->border_geometry = (const struct wlc_geometry){0}; + container->title_bar_geometry = (const struct wlc_geometry){0}; + } else { + // make room for border + container->border_geometry = geometry; + + int border_top = container->border_thickness; + int border_bottom = container->border_thickness; + int border_left = container->border_thickness; + int border_right = container->border_thickness; + + // handle hide_edge_borders + if (config->hide_edge_borders != E_NONE && gap <= 0) { + swayc_t *output = swayc_parent_by_type(container, C_OUTPUT); + const struct wlc_size *size = wlc_output_get_resolution(output->handle); + + if (config->hide_edge_borders == E_HORIZONTAL || config->hide_edge_borders == E_BOTH) { + if (geometry.origin.x == 0) { + border_left = 0; + } + + if (geometry.origin.x + geometry.size.w == size->w) { + border_right = 0; + } + } + + if (config->hide_edge_borders == E_VERTICAL || config->hide_edge_borders == E_BOTH) { + if (geometry.origin.y == 0) { + border_top = 0; + } + + if (geometry.origin.y + geometry.size.h == size->h) { + border_bottom = 0; + } + } + } + + switch (container->border_type) { + case B_NONE: + break; + case B_PIXEL: + geometry.origin.x += border_left; + geometry.origin.y += border_top; + geometry.size.w -= (border_left + border_right); + geometry.size.h -= (border_top + border_bottom); + break; + case B_NORMAL: + { + struct wlc_geometry title_bar = { + .origin = { + .x = container->border_geometry.origin.x, + .y = container->border_geometry.origin.y + }, + .size = { + .w = container->border_geometry.size.w, + .h = config->font_height + 4 // borders + padding + } + }; + geometry.origin.x += border_left; + geometry.origin.y += title_bar.size.h; + geometry.size.w -= (border_left + border_right); + geometry.size.h -= (border_bottom + title_bar.size.h); + container->title_bar_geometry = title_bar; + break; + } + } + + container->actual_geometry = geometry; + + update_view_border(container); + } + wlc_view_set_geometry(container->handle, 0, &geometry); } diff --git a/sway/render.c b/sway/render.c deleted file mode 100644 index 9388c1d0..00000000 --- a/sway/render.c +++ /dev/null @@ -1,113 +0,0 @@ -#include "render.h" -#include -#include -#include -#include -#include "container.h" - -void cairo_set_source_u32(cairo_t *cairo, uint32_t color) { - cairo_set_source_rgba(cairo, - (color >> (3*8) & 0xFF) / 255.0, - (color >> (2*8) & 0xFF) / 255.0, - (color >> (1*8) & 0xFF) / 255.0, - (color >> (0*8) & 0xFF) / 255.0); -} - -cairo_t *create_border_buffer(swayc_t *view, struct wlc_geometry geo, - cairo_surface_t **surface) { - const int channels = 4; - cairo_t *cr; - view->border_geometry = geo; - view->border = calloc(channels * geo.size.w * geo.size.h, - sizeof(unsigned char)); - if (!view->border) { - sway_log(L_DEBUG, "Unable to allocate buffer"); - return NULL; - } - *surface = cairo_image_surface_create_for_data(view->border, - CAIRO_FORMAT_ARGB32, geo.size.w, geo.size.h, channels * geo.size.w); - if (cairo_surface_status(*surface) != CAIRO_STATUS_SUCCESS) { - free(view->border); - view->border = NULL; - sway_log(L_DEBUG, "Unable to allocate surface"); - return NULL; - } - cr = cairo_create(*surface); - if (cairo_status(cr) != CAIRO_STATUS_SUCCESS) { - cairo_surface_destroy(*surface); - free(view->border); - view->border = NULL; - sway_log(L_DEBUG, "Unable to create cairo context"); - return NULL; - } - return cr; -} - -void update_view_border(swayc_t *view) { - struct wlc_geometry geo; - wlc_view_get_visible_geometry(view->handle, &geo); - cairo_t *cr = NULL; - cairo_surface_t *surface = NULL; - - if (view->border) { - free(view->border); - view->border = NULL; - } - - switch (view->border_type) { - case B_NONE: - view->border_geometry = geo; - break; - case B_PIXEL: - geo.origin.x -= view->border_thickness; - geo.origin.y -= view->border_thickness; - geo.size.w += view->border_thickness * 2; - geo.size.h += view->border_thickness * 2; - if (geo.size.w <= 0 || geo.size.h <= 0) { - view->border = NULL; - break; - } - cr = create_border_buffer(view, geo, &surface); - if (!cr) { - break; - } - cairo_set_source_u32(cr, 0x0000FFFF); - cairo_paint(cr); - break; - case B_NORMAL: - // TODO - break; - } - if (surface) { - cairo_surface_flush(surface); - cairo_surface_destroy(surface); - } - if (cr) { - cairo_destroy(cr); - sway_log(L_DEBUG, "Created border for %p (%dx%d+%d,%d)", view, - geo.size.w, geo.size.h, geo.origin.x, geo.origin.y); - } - view->border_geometry = geo; -} - -void render_view_borders(wlc_handle view) { - swayc_t *c = swayc_by_handle(view); - if (!c || c->border_type == B_NONE) { - return; - } - struct wlc_geometry geo; - wlc_view_get_visible_geometry(view, &geo); - if (geo.size.w != c->presumed_geometry.size.w - || geo.size.h != c->presumed_geometry.size.h - || geo.origin.x != c->presumed_geometry.origin.x - || geo.origin.y != c->presumed_geometry.origin.y) { - update_view_border(c); - c->presumed_geometry = geo; - } - if (c->border) { - geo = c->border_geometry; - sway_log(L_DEBUG, "Rendering border for %p (%dx%d+%d,%d)", c, - geo.size.w, geo.size.h, geo.origin.x, geo.origin.y); - wlc_pixels_write(WLC_RGBA8888, &c->border_geometry, c->border); - } -} From a87a5dbdd5cf748649dbe33c1c5072a6aec08929 Mon Sep 17 00:00:00 2001 From: Mikkel Oscar Lyderik Date: Tue, 29 Mar 2016 23:07:20 +0200 Subject: [PATCH 10/14] Comment endianness --- sway/border.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sway/border.c b/sway/border.c index 8c9106e4..872e8d34 100644 --- a/sway/border.c +++ b/sway/border.c @@ -10,13 +10,13 @@ void cairo_set_source_u32(cairo_t *cairo, uint32_t color) { int endian = 1; - if (*(char *)&endian == 1) { + if (*(char *)&endian == 1) { // little endian cairo_set_source_rgba(cairo, (color >> (1*8) & 0xFF) / 255.0, (color >> (2*8) & 0xFF) / 255.0, (color >> (3*8) & 0xFF) / 255.0, (color >> (0*8) & 0xFF) / 255.0); - } else { + } else { // big endian cairo_set_source_rgba(cairo, (color >> (0*8) & 0xFF) / 255.0, (color >> (3*8) & 0xFF) / 255.0, From d80466068aab90cbb14eb88868d684f14b91642c Mon Sep 17 00:00:00 2001 From: Mikkel Oscar Lyderik Date: Tue, 29 Mar 2016 23:31:44 +0200 Subject: [PATCH 11/14] Handle swaybar using sway font --- swaybar/config.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/swaybar/config.c b/swaybar/config.c index fddea791..6b9ff86b 100644 --- a/swaybar/config.c +++ b/swaybar/config.c @@ -35,9 +35,11 @@ uint32_t parse_position(const char *position) { char *parse_font(const char *font) { char *new_font = NULL; if (strncmp("pango:", font, 6) == 0) { - new_font = strdup(font + 6); + font += 6; } + new_font = strdup(font); + return new_font; } From 7878de5ccc223baa609770e04efa151f5b99b16d Mon Sep 17 00:00:00 2001 From: Mikkel Oscar Lyderik Date: Wed, 30 Mar 2016 00:13:39 +0200 Subject: [PATCH 12/14] Mark focused view focus_inactive on unfocused output --- include/border.h | 1 + sway/border.c | 6 ++++++ sway/focus.c | 2 ++ 3 files changed, 9 insertions(+) diff --git a/include/border.h b/include/border.h index 63cd63d2..85c656e0 100644 --- a/include/border.h +++ b/include/border.h @@ -5,6 +5,7 @@ void render_view_borders(wlc_handle view); void update_view_border(swayc_t *view); +void map_update_view_border(swayc_t *view, void *data); int get_font_text_height(const char *font); #endif diff --git a/sway/border.c b/sway/border.c index 872e8d34..e820794f 100644 --- a/sway/border.c +++ b/sway/border.c @@ -170,6 +170,12 @@ static void render_with_title_bar(swayc_t *view, cairo_t *cr, struct border_colo view->actual_geometry.size.w, 1); } +void map_update_view_border(swayc_t *view, void *data) { + if (view->type == C_VIEW) { + update_view_border(view); + } +} + void update_view_border(swayc_t *view) { cairo_t *cr = NULL; cairo_surface_t *surface = NULL; diff --git a/sway/focus.c b/sway/focus.c index 4cae3b47..0c9719b0 100644 --- a/sway/focus.c +++ b/sway/focus.c @@ -29,6 +29,8 @@ static void update_focus(swayc_t *c) { // Case where output changes case C_OUTPUT: + // update borders for views in prev + container_map(prev, map_update_view_border, NULL); wlc_output_focus(c->handle); break; From 6fa6c27f3d5f0f49a050cda6c952ad2595e25f32 Mon Sep 17 00:00:00 2001 From: Mikkel Oscar Lyderik Date: Wed, 30 Mar 2016 00:59:40 +0200 Subject: [PATCH 13/14] Update window title when it changes --- sway/border.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/sway/border.c b/sway/border.c index e820794f..ab4b70f6 100644 --- a/sway/border.c +++ b/sway/border.c @@ -157,11 +157,13 @@ static void render_with_title_bar(swayc_t *view, cairo_t *cr, struct border_colo render_sharp_line(cr, colors->border, 0, 0, tb->size.w, 1); // text - int width, height; - get_text_size(cr, config->font, &width, &height, "%s", view->name); - cairo_move_to(cr, view->border_thickness, 2); - cairo_set_source_u32(cr, colors->text); - pango_printf(cr, config->font, "%s", view->name); + if (view->name) { + int width, height; + get_text_size(cr, config->font, &width, &height, "%s", view->name); + cairo_move_to(cr, view->border_thickness, 2); + cairo_set_source_u32(cr, colors->text); + pango_printf(cr, config->font, "%s", view->name); + } // header bottom line render_sharp_line(cr, colors->border, @@ -247,6 +249,17 @@ void render_view_borders(wlc_handle view) { return; } + if (c->border_type == B_NORMAL) { + // update window title + const char *new_name = wlc_view_get_title(view); + + if (new_name && strcmp(c->name, new_name) != 0) { + free(c->name); + c->name = strdup(new_name); + update_view_border(c); + } + } + if (c->border) { wlc_pixels_write(WLC_RGBA8888, &c->border_geometry, c->border); } From 0af55539a8afe38fa1a1beb6af15b0891030985a Mon Sep 17 00:00:00 2001 From: Mikkel Oscar Lyderik Date: Wed, 30 Mar 2016 10:09:08 +0200 Subject: [PATCH 14/14] Fix borders with floating windows --- sway/handlers.c | 14 +++++++------- sway/layout.c | 45 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 50 insertions(+), 9 deletions(-) diff --git a/sway/handlers.c b/sway/handlers.c index fc473640..54326dd0 100644 --- a/sway/handlers.c +++ b/sway/handlers.c @@ -349,13 +349,13 @@ static void handle_view_geometry_request(wlc_handle handle, const struct wlc_geo view->desired_width = geometry->size.w; view->desired_height = geometry->size.h; - /* if (view->is_floating) { */ - /* view->width = view->desired_width; */ - /* view->height = view->desired_height; */ - /* view->x = geometry->origin.x; */ - /* view->y = geometry->origin.y; */ - /* /1* arrange_windows(view->parent, -1, -1); *1/ */ - /* } */ + if (view->is_floating) { + view->width = view->desired_width; + view->height = view->desired_height; + view->x = geometry->origin.x; + view->y = geometry->origin.y; + arrange_windows(view->parent, -1, -1); + } } } diff --git a/sway/layout.c b/sway/layout.c index a282f36e..3f271caf 100644 --- a/sway/layout.c +++ b/sway/layout.c @@ -374,6 +374,46 @@ void move_workspace_to(swayc_t* workspace, swayc_t* destination) { update_visibility(src_op); } +static void update_border_geometry_floating(swayc_t *c, struct wlc_geometry *geometry) { + struct wlc_geometry g = *geometry; + c->actual_geometry = g; + + switch (c->border_type) { + case B_NONE: + break; + case B_PIXEL: + g.origin.x -= c->border_thickness; + g.origin.y -= c->border_thickness; + g.size.w += (c->border_thickness * 2); + g.size.h += (c->border_thickness * 2); + break; + case B_NORMAL: + g.origin.x -= c->border_thickness; + uint32_t title_bar_height = config->font_height + 4; // borders + padding + g.origin.y -= title_bar_height; + g.size.w += (c->border_thickness * 2); + g.size.h += (c->border_thickness + title_bar_height); + + struct wlc_geometry title_bar = { + .origin = { + .x = g.origin.x, + .y = g.origin.y + }, + .size = { + .w = g.size.w, + .h = title_bar_height + } + }; + c->title_bar_geometry = title_bar; + break; + } + + c->border_geometry = g; + *geometry = c->actual_geometry; + + update_view_border(c); +} + void update_geometry(swayc_t *container) { if (container->type != C_VIEW) { return; @@ -431,8 +471,9 @@ void update_geometry(swayc_t *container) { if (swayc_is_fullscreen(container)) { container->border_geometry = (const struct wlc_geometry){0}; container->title_bar_geometry = (const struct wlc_geometry){0}; - } else { - // make room for border + } else if (container->is_floating) { // allocate border for floating window + update_border_geometry_floating(container, &geometry); + } else if (!container->is_floating) { // allocate border for titled window container->border_geometry = geometry; int border_top = container->border_thickness;