From 34b2374fd005fe08a3a0454e6543151148f424bc Mon Sep 17 00:00:00 2001 From: Johan Malm Date: Sat, 17 Sep 2022 12:24:08 +0100 Subject: [PATCH] Fix minor coding-style violations ...based on https://github.com/johanmalm/checkpatch.pl ``` src/server.c:161: ERROR: space required before the open parenthesis '(' src/server.c:473: CHECK: Blank lines aren't necessary after an open brace '{' src/desktop.c:228: WARNING: function definition argument 'struct wl_list *' should also have an identifier name src/output.c:289: CHECK: Blank lines aren't necessary before a close brace '}' src/interactive.c:20: WARNING: suspect code indent for conditional statements (8, 17) src/interactive.c:27: WARNING: Statements should start on a tabstop src/config/rcxml.c:607: CHECK: Blank lines aren't necessary after an open brace '{' src/config/rcxml.c:638: CHECK: line length of 91 exceeds 90 columns src/config/rcxml.c:639: CHECK: Blank lines aren't necessary after an open brace '{' src/debug.c:126: WARNING: suspect code indent for conditional statements (8, 24) src/debug.c:129: WARNING: suspect code indent for conditional statements (8, 24) src/view.c:307: CHECK: Please use a blank line after function/struct/union/enum declarations src/workspaces.c:52: CHECK: Blank lines aren't necessary after an open brace '{' src/workspaces.c:147: ERROR: space prohibited before that close parenthesis ')' src/workspaces.c:226: CHECK: line length of 91 exceeds 90 columns src/workspaces.c:290: CHECK: Please don't use multiple blank lines src/workspaces.c:328: WARNING: else is not generally useful after a break or return src/cursor.c:18: ERROR: do not initialise statics to NULL src/cursor.c:20: CHECK: Please don't use multiple blank lines src/common/scaled_font_buffer.c:55: CHECK: Assignment operator '=' should be on the previous line src/common/graphic-helpers.c:44: CHECK: Blank lines aren't necessary after an open brace '{' src/common/graphic-helpers.c:71: CHECK: multiple assignments should be avoided src/common/scaled_scene_buffer.c:115: CHECK: Assignment operator '=' should be on the previous line src/common/scaled_scene_buffer.c:135: CHECK: Assignment operator '=' should be on the previous line src/common/fd_util.c:15: CHECK: line length of 106 exceeds 90 columns src/common/fd_util.c:22: CHECK: line length of 106 exceeds 90 columns src/common/fd_util.c:25: ERROR: code indent should use tabs where possible src/common/fd_util.c:25: WARNING: please, no spaces at the start of a line include/workspaces.h:13: ERROR: code indent should use tabs where possible include/workspaces.h:13: WARNING: Block comments use * on subsequent lines include/workspaces.h:13: WARNING: Block comments use a trailing */ on a separate line include/workspaces.h:20: CHECK: Please don't use multiple blank lines include/workspaces.h:26: ERROR: "foo * bar" should be "foo *bar" include/action.h:11: ERROR: code indent should use tabs where possible include/action.h:12: ERROR: code indent should use tabs where possible include/action.h:12: WARNING: Block comments use a trailing */ on a separate line include/common/scaled_scene_buffer.h:62: CHECK: Please don't use multiple blank lines ``` --- include/common/scaled_scene_buffer.h | 1 - include/workspaces.h | 3 +- src/common/fd_util.c | 8 +- src/common/graphic-helpers.c | 1 - src/common/scaled_scene_buffer.c | 8 +- src/debug.c | 4 +- src/desktop.c | 2 +- src/interactive.c | 2 +- src/layers.c.new | 398 +++++++++++++++++++++++++++ src/server.c | 3 +- src/workspaces.c | 4 +- src/xbm/xbm.c.new | 92 +++++++ 12 files changed, 506 insertions(+), 20 deletions(-) create mode 100644 src/layers.c.new create mode 100644 src/xbm/xbm.c.new diff --git a/include/common/scaled_scene_buffer.h b/include/common/scaled_scene_buffer.h index fa2cb91f..2057ab24 100644 --- a/include/common/scaled_scene_buffer.h +++ b/include/common/scaled_scene_buffer.h @@ -59,7 +59,6 @@ struct scaled_scene_buffer *scaled_scene_buffer_create( /* Clear the cache of existing buffers, useful in case the content changes */ void scaled_scene_buffer_invalidate_cache(struct scaled_scene_buffer *self); - /* Private */ struct scaled_scene_buffer_cache_entry { struct wl_list link; /* struct scaled_scene_buffer.cache */ diff --git a/include/workspaces.h b/include/workspaces.h index 8b16bd05..8f77339b 100644 --- a/include/workspaces.h +++ b/include/workspaces.h @@ -17,12 +17,11 @@ struct workspace { struct wlr_scene_tree *tree; }; - void workspaces_init(struct server *server); void workspaces_switch_to(struct workspace *target); void workspaces_send_to(struct view *view, struct workspace *target); void workspaces_destroy(struct server *server); void workspaces_osd_hide(struct seat *seat); -struct workspace * workspaces_find(struct workspace *anchor, const char *name); +struct workspace *workspaces_find(struct workspace *anchor, const char *name); #endif /* __LABWC_WORKSPACES_H */ diff --git a/src/common/fd_util.c b/src/common/fd_util.c index f45cad83..e935f02c 100644 --- a/src/common/fd_util.c +++ b/src/common/fd_util.c @@ -12,17 +12,19 @@ void increase_nofile_limit(void) { if (getrlimit(RLIMIT_NOFILE, &original_nofile_rlimit) != 0) { - wlr_log_errno(WLR_ERROR, "Failed to bump max open files limit: getrlimit(NOFILE) failed"); + wlr_log_errno(WLR_ERROR, + "Failed to bump max open files limit: getrlimit(NOFILE) failed"); return; } struct rlimit new_rlimit = original_nofile_rlimit; new_rlimit.rlim_cur = new_rlimit.rlim_max; if (setrlimit(RLIMIT_NOFILE, &new_rlimit) != 0) { - wlr_log_errno(WLR_ERROR, "Failed to bump max open files limit: setrlimit(NOFILE) failed"); + wlr_log_errno(WLR_ERROR, + "Failed to bump max open files limit: setrlimit(NOFILE) failed"); wlr_log(WLR_INFO, "Running with %d max open files", - (int)original_nofile_rlimit.rlim_cur); + (int)original_nofile_rlimit.rlim_cur); } } diff --git a/src/common/graphic-helpers.c b/src/common/graphic-helpers.c index eb147893..b820e170 100644 --- a/src/common/graphic-helpers.c +++ b/src/common/graphic-helpers.c @@ -41,7 +41,6 @@ multi_rect_set_size(struct multi_rect *rect, int width, int height) int line_width = rect->line_width; for (size_t i = 0; i < 3; i++) { - /* Reposition, top and left don't ever change */ wlr_scene_node_set_position(&rect->right[i]->node, width - (i + 1) * line_width, i * line_width); diff --git a/src/common/scaled_scene_buffer.c b/src/common/scaled_scene_buffer.c index 95e2673d..1ae95a94 100644 --- a/src/common/scaled_scene_buffer.c +++ b/src/common/scaled_scene_buffer.c @@ -111,8 +111,8 @@ _handle_node_destroy(struct wl_listener *listener, void *data) static void _handle_output_enter(struct wl_listener *listener, void *data) { - struct scaled_scene_buffer *self - = wl_container_of(listener, self, output_enter); + struct scaled_scene_buffer *self = + wl_container_of(listener, self, output_enter); /* primary_output is the output most of the node area is in */ struct wlr_scene_output *primary = self->scene_buffer->primary_output; /* scene_output is the output we just entered */ @@ -131,8 +131,8 @@ _handle_output_enter(struct wl_listener *listener, void *data) static void _handle_output_leave(struct wl_listener *listener, void *data) { - struct scaled_scene_buffer *self - = wl_container_of(listener, self, output_leave); + struct scaled_scene_buffer *self = + wl_container_of(listener, self, output_leave); /* primary_output is the output most of the node area is in */ struct wlr_scene_output *primary = self->scene_buffer->primary_output; diff --git a/src/debug.c b/src/debug.c index 8c336ec4..815748d1 100644 --- a/src/debug.c +++ b/src/debug.c @@ -124,10 +124,10 @@ get_special(struct server *server, struct wlr_scene_node *node, struct wlr_scene_tree *grand_parent = node->parent ? node->parent->node.parent : NULL; if (grand_parent == server->view_tree) { - *last_view = node_view_from_node(node); + *last_view = node_view_from_node(node); } if (node->parent == server->view_tree_always_on_top) { - *last_view = node_view_from_node(node); + *last_view = node_view_from_node(node); } const char *view_part = get_view_part(*last_view, node); if (view_part) { diff --git a/src/desktop.c b/src/desktop.c index a867c1f0..a080e8db 100644 --- a/src/desktop.c +++ b/src/desktop.c @@ -225,7 +225,7 @@ desktop_cycle_view(struct server *server, struct view *start_view, assert(node->parent); struct wl_list *list_head = &node->parent->children; struct wl_list *list_item = &node->link; - struct wl_list *(*iter)(struct wl_list *); + struct wl_list *(*iter)(struct wl_list *list); /* Scene nodes are ordered like last node == displayed topmost */ iter = dir == LAB_CYCLE_DIR_FORWARD ? get_prev_item : get_next_item; diff --git a/src/interactive.c b/src/interactive.c index de47d09d..99622fc1 100644 --- a/src/interactive.c +++ b/src/interactive.c @@ -24,7 +24,7 @@ interactive_begin(struct view *view, enum input_mode mode, uint32_t edges) * If you think there is a good reason to allow it * feel free to open an issue explaining your use-case. */ - return; + return; } if (mode == LAB_INPUT_STATE_RESIZE && (view->fullscreen || view->maximized)) { diff --git a/src/layers.c.new b/src/layers.c.new new file mode 100644 index 00000000..fe63b3d3 --- /dev/null +++ b/src/layers.c.new @@ -0,0 +1,398 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * layers.c - layer-shell implementation + * + * Based on + * - https://git.sr.ht/~sircmpwm/wio + * - https://github.com/swaywm/sway + * Copyright (C) 2019 Drew DeVault and Sway developers + */ + +#include +#include +#include +#include +#include +#include +#include "layers.h" +#include "labwc.h" +#include "node.h" + +void +layers_arrange(struct output *output) +{ + struct wlr_box full_area = { 0 }; + wlr_output_effective_resolution(output->wlr_output, + &full_area.width, &full_area.height); + struct wlr_box usable_area = full_area; + struct wlr_box old_usable_area = output->usable_area; + + struct server *server = output->server; + struct wlr_scene_output *scene_output = + wlr_scene_get_scene_output(server->scene, output->wlr_output); + if (!scene_output) { + wlr_log(WLR_DEBUG, "no wlr_scene_output"); + return; + } + + int nr_layers = sizeof(output->layers) / sizeof(output->layers[0]); + for (int i = 0; i < nr_layers; i++) { + struct lab_layer_surface *lab_layer_surface; + + /* + * First we go over the list of surfaces that have + * exclusive_zone set (e.g. statusbars) because we have to + * determine the usable area before processing regular layouts. + */ + wl_list_for_each(lab_layer_surface, &output->layers[i], link) { + struct wlr_scene_layer_surface_v1 *scene_layer_surface = + lab_layer_surface->scene_layer_surface; + if (scene_layer_surface->layer_surface->current.exclusive_zone) { + wlr_scene_layer_surface_v1_configure( + scene_layer_surface, &full_area, &usable_area); + } + } + + /* Now we process regular layouts */ + wl_list_for_each(lab_layer_surface, &output->layers[i], link) { + struct wlr_scene_layer_surface_v1 *scene_layer_surface = + lab_layer_surface->scene_layer_surface; + if (!scene_layer_surface->layer_surface->current.exclusive_zone) { + wlr_scene_layer_surface_v1_configure( + scene_layer_surface, &full_area, &usable_area); + } + } + + wlr_scene_node_set_position(&output->layer_tree[i]->node, + scene_output->x, scene_output->y); + } + + memcpy(&output->usable_area, &usable_area, sizeof(struct wlr_box)); + + /* Find topmost keyboard interactive layer, if such a layer exists */ + uint32_t layers_above_shell[] = { + ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, + ZWLR_LAYER_SHELL_V1_LAYER_TOP, + }; + size_t nlayers = sizeof(layers_above_shell) + / sizeof(layers_above_shell[0]); + struct lab_layer_surface *layer, *topmost = NULL; + for (size_t i = 0; i < nlayers; ++i) { + wl_list_for_each_reverse (layer, + &output->layers[layers_above_shell[i]], link) { + struct wlr_layer_surface_v1 *layer_surface = + layer->scene_layer_surface->layer_surface; + if (layer_surface->current.keyboard_interactive) { + topmost = layer; + break; + } + } + if (topmost) { + break; + } + } + struct seat *seat = &output->server->seat; + if (topmost) { + seat_set_focus_layer(seat, + topmost->scene_layer_surface->layer_surface); + } else if (seat->focused_layer && + !seat->focused_layer->current.keyboard_interactive) { + seat_set_focus_layer(seat, NULL); + } + + /* Finally re-arrange all views based on usable_area */ + if (old_usable_area.width != output->usable_area.width + || old_usable_area.height != output->usable_area.height) { + desktop_arrange_all_views(server); + } +} + +static void +output_destroy_notify(struct wl_listener *listener, void *data) +{ + struct lab_layer_surface *layer = + wl_container_of(listener, layer, output_destroy); + layer->scene_layer_surface->layer_surface->output = NULL; +} + +static void +surface_commit_notify(struct wl_listener *listener, void *data) +{ + struct lab_layer_surface *layer = + wl_container_of(listener, layer, surface_commit); + struct wlr_layer_surface_v1 *layer_surface = + layer->scene_layer_surface->layer_surface; + struct wlr_output *wlr_output = + layer->scene_layer_surface->layer_surface->output; + + if (!wlr_output) { + return; + } + + if (layer_surface->current.committed + || layer->mapped != layer_surface->mapped) { + layer->mapped = layer_surface->mapped; + struct output *output = + output_from_wlr_output(layer->server, wlr_output); + layers_arrange(output); + } +} + +static void +unmap(struct lab_layer_surface *layer) +{ + struct seat *seat = &layer->server->seat; + if (seat->focused_layer == layer->scene_layer_surface->layer_surface) { + seat_set_focus_layer(seat, NULL); + } + if (seat->pressed.surface == layer->scene_layer_surface->layer_surface->surface) { + seat->pressed.node = NULL; + seat->pressed.surface = NULL; + } +} + +static void +destroy_notify(struct wl_listener *listener, void *data) +{ + struct lab_layer_surface *layer = wl_container_of( + listener, layer, destroy); + unmap(layer); + + wl_list_remove(&layer->link); + wl_list_remove(&layer->destroy.link); + wl_list_remove(&layer->map.link); + wl_list_remove(&layer->unmap.link); + wl_list_remove(&layer->surface_commit.link); + if (layer->scene_layer_surface->layer_surface->output) { + wl_list_remove(&layer->output_destroy.link); + struct output *output = output_from_wlr_output(layer->server, + layer->scene_layer_surface->layer_surface->output); + layers_arrange(output); + } + free(layer); +} + +static void +unmap_notify(struct wl_listener *listener, void *data) +{ + struct lab_layer_surface *lab_layer_surface = + wl_container_of(listener, lab_layer_surface, unmap); + unmap(lab_layer_surface); +} + +static void +map_notify(struct wl_listener *listener, void *data) +{ + struct wlr_layer_surface_v1 *layer_surface = data; + wlr_surface_send_enter(layer_surface->surface, layer_surface->output); +} + +static void +popup_handle_destroy(struct wl_listener *listener, void *data) +{ + struct lab_layer_popup *popup = + wl_container_of(listener, popup, destroy); + wl_list_remove(&popup->destroy.link); + wl_list_remove(&popup->new_popup.link); + free(popup); +} + +static void popup_handle_new_popup(struct wl_listener *listener, void *data); + +static struct lab_layer_popup * +create_popup(struct wlr_xdg_popup *wlr_popup, struct wlr_scene_tree *parent, + struct wlr_box *output_toplevel_sx_box) +{ + struct lab_layer_popup *popup = + calloc(1, sizeof(struct lab_layer_popup)); + if (!popup) { + return NULL; + } + + popup->wlr_popup = wlr_popup; + popup->scene_tree = + wlr_scene_xdg_surface_create(parent, wlr_popup->base); + if (!popup->scene_tree) { + free(popup); + return NULL; + } + node_descriptor_create(&popup->scene_tree->node, + LAB_NODE_DESC_LAYER_POPUP, popup); + + popup->destroy.notify = popup_handle_destroy; + wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy); + popup->new_popup.notify = popup_handle_new_popup; + wl_signal_add(&wlr_popup->base->events.new_popup, &popup->new_popup); + + wlr_xdg_popup_unconstrain_from_box(wlr_popup, output_toplevel_sx_box); + return popup; +} + +/* This popup's parent is a layer popup */ +static void +popup_handle_new_popup(struct wl_listener *listener, void *data) +{ + struct lab_layer_popup *lab_layer_popup = + wl_container_of(listener, lab_layer_popup, new_popup); + struct wlr_xdg_popup *wlr_popup = data; + struct lab_layer_popup *new_popup = create_popup(wlr_popup, + lab_layer_popup->scene_tree, + &lab_layer_popup->output_toplevel_sx_box); + new_popup->output_toplevel_sx_box = + lab_layer_popup->output_toplevel_sx_box; +} + +/* + * We move popups from the bottom to the top layer so that they are + * rendered above views. + */ +static void +move_popup_to_top_layer(struct lab_layer_surface *toplevel, + struct lab_layer_popup *popup) +{ + struct server *server = toplevel->server; + struct wlr_output *wlr_output = + toplevel->scene_layer_surface->layer_surface->output; + struct output *output = output_from_wlr_output(server, wlr_output); + struct wlr_box box = { 0 }; + wlr_output_layout_get_box(server->output_layout, wlr_output, &box); + int lx = toplevel->scene_layer_surface->tree->node.x + box.x; + int ly = toplevel->scene_layer_surface->tree->node.y + box.y; + + struct wlr_scene_node *node = &popup->scene_tree->node; + wlr_scene_node_reparent(node, output->layer_popup_tree); + /* FIXME: verify the whole tree should be repositioned */ + wlr_scene_node_set_position(&output->layer_popup_tree->node, lx, ly); +} + +/* This popup's parent is a shell-layer surface */ +static void +new_popup_notify(struct wl_listener *listener, void *data) +{ + struct lab_layer_surface *toplevel = + wl_container_of(listener, toplevel, new_popup); + struct wlr_xdg_popup *wlr_popup = data; + + int lx, ly; + struct server *server = toplevel->server; + struct wlr_scene_layer_surface_v1 *surface = toplevel->scene_layer_surface; + wlr_scene_node_coords(&surface->tree->node, &lx, &ly); + + if (!surface->layer_surface->output) { + /* Work-around for moving layer shell surfaces on output destruction */ + struct wlr_output *wlr_output; + wlr_output = wlr_output_layout_output_at(server->output_layout, lx, ly); + surface->layer_surface->output = wlr_output; + } + struct output *output = surface->layer_surface->output->data; + + struct wlr_box output_box = { 0 }; + wlr_output_layout_get_box(server->output_layout, + output->wlr_output, &output_box); + + /* + * Output geometry expressed in the coordinate system of the toplevel + * parent of popup. We store this struct the lab_layer_popup struct + * to make it easier to unconstrain children when we move popups from + * the bottom to the top layer. + */ + struct wlr_box output_toplevel_sx_box = { + .x = output_box.x - lx, + .y = output_box.y - ly, + .width = output_box.width, + .height = output_box.height, + }; + struct lab_layer_popup *popup = create_popup(wlr_popup, + surface->tree, &output_toplevel_sx_box); + popup->output_toplevel_sx_box = output_toplevel_sx_box; + + if (surface->layer_surface->current.layer + == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM) { + move_popup_to_top_layer(toplevel, popup); + } +} + +static void +new_layer_surface_notify(struct wl_listener *listener, void *data) +{ + struct server *server = wl_container_of( + listener, server, new_layer_surface); + struct wlr_layer_surface_v1 *layer_surface = data; + + if (!layer_surface->output) { + struct wlr_output *output = wlr_output_layout_output_at( + server->output_layout, server->seat.cursor->x, + server->seat.cursor->y); + layer_surface->output = output; + } + + struct lab_layer_surface *surface = + calloc(1, sizeof(struct lab_layer_surface)); + if (!surface) { + return; + } + + surface->surface_commit.notify = surface_commit_notify; + wl_signal_add(&layer_surface->surface->events.commit, + &surface->surface_commit); + + surface->destroy.notify = destroy_notify; + wl_signal_add(&layer_surface->events.destroy, &surface->destroy); + + surface->map.notify = map_notify; + wl_signal_add(&layer_surface->events.map, &surface->map); + + surface->unmap.notify = unmap_notify; + wl_signal_add(&layer_surface->events.unmap, &surface->unmap); + + surface->new_popup.notify = new_popup_notify; + wl_signal_add(&layer_surface->events.new_popup, &surface->new_popup); + + struct output *output = layer_surface->output->data; + + struct wlr_scene_tree *selected_layer = + output->layer_tree[layer_surface->current.layer]; + + surface->scene_layer_surface = wlr_scene_layer_surface_v1_create( + selected_layer, layer_surface); + if (!surface->scene_layer_surface) { + wlr_layer_surface_v1_destroy(layer_surface); + wlr_log(WLR_ERROR, "could not create layer surface"); + return; + } + + node_descriptor_create(&surface->scene_layer_surface->tree->node, + LAB_NODE_DESC_LAYER_SURFACE, surface); + + surface->server = server; + surface->scene_layer_surface->layer_surface = layer_surface; + + surface->output_destroy.notify = output_destroy_notify; + wl_signal_add(&layer_surface->output->events.destroy, + &surface->output_destroy); + + if (!output) { + wlr_log(WLR_ERROR, "no output for layer"); + return; + } + + wl_list_insert(output->layers[layer_surface->pending.layer].prev, + &surface->link); + /* + * Temporarily set the layer's current state to pending so that + * it can easily be arranged. + */ + struct wlr_layer_surface_v1_state old_state = layer_surface->current; + layer_surface->current = layer_surface->pending; + layers_arrange(output); + layer_surface->current = old_state; +} + +void +layers_init(struct server *server) +{ + server->layer_shell = wlr_layer_shell_v1_create(server->wl_display); + server->new_layer_surface.notify = new_layer_surface_notify; + wl_signal_add(&server->layer_shell->events.new_surface, + &server->new_layer_surface); +} diff --git a/src/server.c b/src/server.c index c2532a5b..5371a0d8 100644 --- a/src/server.c +++ b/src/server.c @@ -158,7 +158,7 @@ handle_drm_lease_request(struct wl_listener *listener, void *data) return; } - for(size_t i = 0; i < req->n_connectors; ++i) { + for (size_t i = 0; i < req->n_connectors; ++i) { struct output *output = req->connectors[i]->output->data; if (!output) { continue; @@ -470,7 +470,6 @@ server_start(struct server *server) void server_finish(struct server *server) { - #if HAVE_XWAYLAND wlr_xwayland_destroy(server->xwayland); #endif diff --git a/src/workspaces.c b/src/workspaces.c index b6a9f664..894a061d 100644 --- a/src/workspaces.c +++ b/src/workspaces.c @@ -49,7 +49,6 @@ parse_workspace_index(const char *name) static void _osd_update(struct server *server) { - struct theme *theme = server->theme; /* Settings */ @@ -138,7 +137,7 @@ _osd_update(struct server *server) + (output->usable_area.width - width) / 2 + output_box.x; int ly = output->usable_area.y - + (output->usable_area.height - height ) / 2 + + (output->usable_area.height - height) / 2 + output_box.y; wlr_scene_node_set_position(&output->workspace_osd->node, lx, ly); wlr_scene_buffer_set_buffer(output->workspace_osd, &buffer->base); @@ -281,7 +280,6 @@ workspaces_send_to(struct view *view, struct workspace *target) view->workspace = target; } - void workspaces_osd_hide(struct seat *seat) { diff --git a/src/xbm/xbm.c.new b/src/xbm/xbm.c.new new file mode 100644 index 00000000..f11da471 --- /dev/null +++ b/src/xbm/xbm.c.new @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Create pixmaps based on xbm data + * + * Copyright Johan Malm 2020 + */ + +#include +#include +#include + +#include "common/dir.h" +#include "common/grab-file.h" +#include "config/rcxml.h" +#include "theme.h" +#include "xbm/parse.h" +#include "xbm/xbm.h" +#include "buffer.h" + +/* built-in 6x6 buttons */ +char menu_button_normal[] = { 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00 }; +char iconify_button_normal[] = { 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f }; +char max_button_normal[] = { 0x3f, 0x3f, 0x21, 0x21, 0x21, 0x3f }; +char max_button_toggled[] = { 0x3e, 0x22, 0x2f, 0x29, 0x39, 0x0f }; +char close_button_normal[] = { 0x33, 0x3f, 0x1e, 0x1e, 0x3f, 0x33 }; + +static char * +xbm_path(const char *button) +{ + static char buffer[4096] = { 0 }; + snprintf(buffer, sizeof(buffer), "%s/%s", theme_dir(rc.theme_name), + button); + return buffer; +} + +static void +load_button(const char *filename, struct lab_data_buffer **buffer, char *button) +{ + struct pixmap pixmap = {0}; + if (*buffer) { + wlr_buffer_drop(&(*buffer)->base); + *buffer = NULL; + } + + /* Read file into memory as it's easier to tokenzie that way */ + char *token_buffer = grab_file(xbm_path(filename)); + if (token_buffer) { + struct token *tokens = tokenize_xbm(token_buffer); + free(token_buffer); + pixmap = parse_xbm_tokens(tokens); + if (tokens) { + free(tokens); + } + } + if (!pixmap.data) { + pixmap = parse_xbm_builtin(button, 6); + } + + /* Create buffer with free_on_destroy being true */ + *buffer = buffer_create_wrap(pixmap.data, pixmap.width, pixmap.height, + pixmap.width * 4, true); +} + +void +xbm_load(struct theme *theme) +{ + parse_set_color(theme->window_active_button_menu_unpressed_image_color); + load_button("menu.xbm", &theme->xbm_menu_active_unpressed, + menu_button_normal); + parse_set_color(theme->window_active_button_iconify_unpressed_image_color); + load_button("iconify.xbm", &theme->xbm_iconify_active_unpressed, + iconify_button_normal); + parse_set_color(theme->window_active_button_max_unpressed_image_color); + load_button("max.xbm", &theme->xbm_maximize_active_unpressed, + max_button_normal); + parse_set_color(theme->window_active_button_close_unpressed_image_color); + load_button("close.xbm", &theme->xbm_close_active_unpressed, + close_button_normal); + + parse_set_color(theme->window_inactive_button_menu_unpressed_image_color); + load_button("menu.xbm", &theme->xbm_menu_inactive_unpressed, + menu_button_normal); + parse_set_color(theme->window_inactive_button_iconify_unpressed_image_color); + load_button("iconify.xbm", &theme->xbm_iconify_inactive_unpressed, + iconify_button_normal); + parse_set_color(theme->window_inactive_button_max_unpressed_image_color); + load_button("max.xbm", &theme->xbm_maximize_inactive_unpressed, + max_button_normal); + parse_set_color(theme->window_inactive_button_close_unpressed_image_color); + load_button("close.xbm", &theme->xbm_close_inactive_unpressed, + close_button_normal); +}