From 29a26d5ff700dc8288d378da5f96b3cd67aacd86 Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Thu, 8 Feb 2024 14:23:06 +0100 Subject: [PATCH 01/33] edges: do not apply resistance to invisible edges --- include/edges.h | 7 +- include/view.h | 1 + src/edges.c | 235 +++++++++++++++++++++++++++++++++++++++++----- src/interactive.c | 4 + src/resistance.c | 10 +- src/snap.c | 15 +-- 6 files changed, 235 insertions(+), 37 deletions(-) diff --git a/include/edges.h b/include/edges.h index 4e7549eb..6ce029c3 100644 --- a/include/edges.h +++ b/include/edges.h @@ -3,11 +3,15 @@ #define LABWC_EDGES_H #include +#include +#include #include "common/macros.h" struct border; struct output; +struct server; struct view; +struct wlr_box; static inline int clipped_add(int a, int b) @@ -102,7 +106,7 @@ void edges_adjust_geom(struct view *view, struct border edges, void edges_find_neighbors(struct border *nearest_edges, struct view *view, struct wlr_box target, struct output *output, - edge_validator_t validator, bool use_pending); + edge_validator_t validator, bool use_pending, bool ignore_hidden); void edges_find_outputs(struct border *nearest_edges, struct view *view, struct wlr_box target, struct output *output, @@ -116,4 +120,5 @@ void edges_adjust_resize_geom(struct view *view, struct border edges, bool edges_traverse_edge(struct edge current, struct edge target, struct edge edge); +void edges_calculate_visibility(struct server *server, struct view *ignored_view); #endif /* LABWC_EDGES_H */ diff --git a/include/view.h b/include/view.h index fdedbe14..c24fa3d3 100644 --- a/include/view.h +++ b/include/view.h @@ -166,6 +166,7 @@ struct view { bool tearing_hint; bool visible_on_all_workspaces; enum view_edge tiled; + uint32_t edges_visible; /* enum wlr_edges bitset */ bool inhibits_keybinds; xkb_layout_index_t keyboard_layout; diff --git a/src/edges.c b/src/edges.c index 86736a4d..b5630a6e 100644 --- a/src/edges.c +++ b/src/edges.c @@ -1,6 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only #include #include +#include +#include #include #include "common/border.h" #include "common/macros.h" @@ -8,6 +10,7 @@ #include "edges.h" #include "labwc.h" #include "view.h" +#include "node.h" static void edges_for_target_geometry(struct border *edges, struct view *view, @@ -35,34 +38,54 @@ edges_initialize(struct border *edges) } static inline struct edge -build_edge(struct border region, enum view_edge direction, int pad) +build_edge(struct border region, enum wlr_edges direction, int pad) { struct edge edge = { 0 }; switch (direction) { - case VIEW_EDGE_LEFT: + case WLR_EDGE_LEFT: edge.offset = clipped_sub(region.left, pad); edge.min = region.top; edge.max = region.bottom; break; - case VIEW_EDGE_RIGHT: + case WLR_EDGE_RIGHT: edge.offset = clipped_add(region.right, pad); edge.min = region.top; edge.max = region.bottom; break; - case VIEW_EDGE_UP: + case WLR_EDGE_TOP: edge.offset = clipped_sub(region.top, pad); edge.min = region.left; edge.max = region.right; break; - case VIEW_EDGE_DOWN: + case WLR_EDGE_BOTTOM: edge.offset = clipped_add(region.bottom, pad); edge.min = region.left; edge.max = region.right; break; - default: + case WLR_EDGE_NONE: /* Should never be reached */ - assert(false); + wlr_log(WLR_ERROR, "invalid direction"); + abort(); + } + + return edge; +} + +static inline bool +is_lesser(enum wlr_edges direction) +{ + return direction == WLR_EDGE_LEFT || direction == WLR_EDGE_TOP; +} + +static inline struct edge +build_visible_edge(struct border region, enum wlr_edges direction, + int pad, uint32_t edges_visible) +{ + struct edge edge = build_edge(region, direction, pad); + + if (!(edges_visible & direction)) { + edge.offset = is_lesser(direction) ? INT_MIN : INT_MAX; } return edge; @@ -72,7 +95,7 @@ static void validate_single_region_edge(int *valid_edge, struct border view, struct border target, struct border region, edge_validator_t validator, - enum view_edge direction) + enum wlr_edges direction, uint32_t edges_visible) { /* * When a view snaps to another while moving to its target, it can do @@ -90,42 +113,63 @@ validate_single_region_edge(int *valid_edge, * the region borders for aligned edges only. */ - bool lesser = direction == VIEW_EDGE_LEFT || direction == VIEW_EDGE_UP; + enum wlr_edges opposing = WLR_EDGE_NONE; + + switch (direction) { + case WLR_EDGE_TOP: + opposing = WLR_EDGE_BOTTOM; + break; + case WLR_EDGE_BOTTOM: + opposing = WLR_EDGE_TOP; + break; + case WLR_EDGE_LEFT: + opposing = WLR_EDGE_RIGHT; + break; + case WLR_EDGE_RIGHT: + opposing = WLR_EDGE_LEFT; + break; + case WLR_EDGE_NONE: + /* Should never be reached */ + assert(false); + return; + } validator(valid_edge, build_edge(view, direction, 0), build_edge(target, direction, 0), - build_edge(region, view_edge_invert(direction), 0), - build_edge(region, direction, rc.gap), lesser); + build_visible_edge(region, opposing, 0, edges_visible), + build_visible_edge(region, direction, rc.gap, edges_visible), + is_lesser(direction)); } static void validate_edges(struct border *valid_edges, struct border view, struct border target, - struct border region, edge_validator_t validator) + struct border region, uint32_t edges_visible, + edge_validator_t validator) { /* Check for edges encountered during movement of left edge */ validate_single_region_edge(&valid_edges->left, - view, target, region, validator, VIEW_EDGE_LEFT); + view, target, region, validator, WLR_EDGE_LEFT, edges_visible); /* Check for edges encountered during movement of right edge */ validate_single_region_edge(&valid_edges->right, - view, target, region, validator, VIEW_EDGE_RIGHT); + view, target, region, validator, WLR_EDGE_RIGHT, edges_visible); /* Check for edges encountered during movement of top edge */ validate_single_region_edge(&valid_edges->top, - view, target, region, validator, VIEW_EDGE_UP); + view, target, region, validator, WLR_EDGE_TOP, edges_visible); /* Check for edges encountered during movement of bottom edge */ validate_single_region_edge(&valid_edges->bottom, - view, target, region, validator, VIEW_EDGE_DOWN); + view, target, region, validator, WLR_EDGE_BOTTOM, edges_visible); } static void validate_single_output_edge(int *valid_edge, struct border view, struct border target, struct border region, edge_validator_t validator, - enum view_edge direction) + enum wlr_edges direction) { static struct border unbounded = { .top = INT_MIN, @@ -134,13 +178,11 @@ validate_single_output_edge(int *valid_edge, .left = INT_MIN, }; - bool lesser = direction == VIEW_EDGE_LEFT || direction == VIEW_EDGE_UP; - validator(valid_edge, build_edge(view, direction, 0), build_edge(target, direction, 0), build_edge(region, direction, 0), - build_edge(unbounded, direction, 0), lesser); + build_edge(unbounded, direction, 0), is_lesser(direction)); } static void @@ -182,27 +224,160 @@ validate_output_edges(struct border *valid_edges, /* Left edge encounters a half-infinite region to the left of the output */ validate_single_output_edge(&valid_edges->left, - view, target, output, validator, VIEW_EDGE_LEFT); + view, target, output, validator, WLR_EDGE_LEFT); /* Right edge encounters a half-infinite region to the right of the output */ validate_single_output_edge(&valid_edges->right, - view, target, output, validator, VIEW_EDGE_RIGHT); + view, target, output, validator, WLR_EDGE_RIGHT); /* Top edge encounters a half-infinite region above the output */ validate_single_output_edge(&valid_edges->top, - view, target, output, validator, VIEW_EDGE_UP); + view, target, output, validator, WLR_EDGE_TOP); /* Bottom edge encounters a half-infinite region below the output */ validate_single_output_edge(&valid_edges->bottom, - view, target, output, validator, VIEW_EDGE_DOWN); + view, target, output, validator, WLR_EDGE_BOTTOM); +} + +/* Test if parts of the current view is covered by the remaining space in the region */ +static void +subtract_view_from_space(struct view *view, pixman_region32_t *available) +{ + struct wlr_box view_size = ssd_max_extents(view); + pixman_box32_t view_rect = { + .x1 = view_size.x, + .x2 = view_size.x + view_size.width, + .y1 = view_size.y, + .y2 = view_size.y + view_size.height + }; + + pixman_region_overlap_t overlap = + pixman_region32_contains_rectangle(available, &view_rect); + + switch (overlap) { + case PIXMAN_REGION_IN: + view->edges_visible = WLR_EDGE_TOP | WLR_EDGE_RIGHT + | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT; + break; + case PIXMAN_REGION_OUT: + view->edges_visible = 0; + return; + case PIXMAN_REGION_PART: + ; /* works around "a label can only be part of a statement" */ + pixman_region32_t intersection; + pixman_region32_init(&intersection); + pixman_region32_intersect_rect(&intersection, available, + view_size.x, view_size.y, + view_size.width, view_size.height); + + int nrects; + const pixman_box32_t *rects = + pixman_region32_rectangles(&intersection, &nrects); + + view->edges_visible = 0; + for (int i = 0; i < nrects; i++) { + if (rects[i].x1 == view_rect.x1) { + view->edges_visible |= WLR_EDGE_LEFT; + } + if (rects[i].y1 == view_rect.y1) { + view->edges_visible |= WLR_EDGE_TOP; + } + if (rects[i].x2 == view_rect.x2) { + view->edges_visible |= WLR_EDGE_RIGHT; + } + if (rects[i].y2 == view_rect.y2) { + view->edges_visible |= WLR_EDGE_BOTTOM; + } + } + pixman_region32_fini(&intersection); + break; + } + + /* Subtract the view geometry from the available region for the next check */ + pixman_region32_t view_region; + pixman_region32_init_rects(&view_region, &view_rect, 1); + pixman_region32_subtract(available, available, &view_region); + pixman_region32_fini(&view_region); +} + +static void +subtract_node_tree(struct wlr_scene_tree *tree, pixman_region32_t *available, + struct view *ignored_view) +{ + struct view *view; + struct wlr_scene_node *node; + struct node_descriptor *node_desc; + wl_list_for_each_reverse(node, &tree->children, link) { + if (!node->enabled) { + /* + * This skips everything that is not being + * rendered, including minimized / unmapped + * windows and workspaces other than the + * current one. + */ + continue; + } + + node_desc = node->data; + if (node_desc && node_desc->type == LAB_NODE_DESC_VIEW) { + view = node_view_from_node(node); + if (view != ignored_view) { + subtract_view_from_space(view, available); + } + } else if (node->type == WLR_SCENE_NODE_TREE) { + subtract_node_tree(wlr_scene_tree_from_node(node), + available, ignored_view); + } + } +} + +void +edges_calculate_visibility(struct server *server, struct view *ignored_view) +{ + /* + * The region stores the available output layout space + * and subtracts the window geometries in reverse rendering + * order, e.g. a window rendered on top is subtracted first. + * + * This allows to detect if a window is actually visible. + * If there is no overlap of its geometry and the remaining + * region it must be completely covered by other windows. + * + */ + pixman_region32_t region; + pixman_region32_init(®ion); + + /* + * Initialize the region with each individual output. + * + * If we were to use NULL for the reference output we + * would get a single combined wlr_box of the whole + * layout which could cover actual invisible areas + * in case the output resolutions differ. + */ + struct output *output; + struct wlr_box layout_box; + wl_list_for_each(output, &server->outputs, link) { + if (!output_is_usable(output)) { + continue; + } + wlr_output_layout_get_box(server->output_layout, + output->wlr_output, &layout_box); + pixman_region32_union_rect(®ion, ®ion, + layout_box.x, layout_box.y, layout_box.width, layout_box.height); + } + + subtract_node_tree(&server->scene->tree, ®ion, ignored_view); + + pixman_region32_fini(®ion); } void edges_find_neighbors(struct border *nearest_edges, struct view *view, struct wlr_box target, struct output *output, - edge_validator_t validator, bool use_pending) + edge_validator_t validator, bool use_pending, bool ignore_hidden) { assert(view); assert(validator); @@ -223,6 +398,14 @@ edges_find_neighbors(struct border *nearest_edges, struct view *view, continue; } + uint32_t edges_visible = ignore_hidden ? v->edges_visible : + WLR_EDGE_TOP | WLR_EDGE_LEFT + | WLR_EDGE_BOTTOM | WLR_EDGE_RIGHT; + + if (edges_visible == 0) { + continue; + } + if (output && v->output != output) { continue; } @@ -252,7 +435,7 @@ edges_find_neighbors(struct border *nearest_edges, struct view *view, }; validate_edges(nearest_edges, view_edges, - target_edges, win_edges, validator); + target_edges, win_edges, edges_visible, validator); } } diff --git a/src/interactive.c b/src/interactive.c index 432027a6..f4b09e1d 100644 --- a/src/interactive.c +++ b/src/interactive.c @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only +#include "edges.h" #include "input/keyboard.h" #include "labwc.h" #include "regions.h" @@ -123,6 +124,9 @@ interactive_begin(struct view *view, enum input_mode mode, uint32_t edges) if (rc.resize_indicator) { resize_indicator_show(view); } + if (rc.window_edge_strength) { + edges_calculate_visibility(server, view); + } } /* Returns true if view was snapped to any edge */ diff --git a/src/resistance.c b/src/resistance.c index e7869fc1..7d317de8 100644 --- a/src/resistance.c +++ b/src/resistance.c @@ -114,8 +114,9 @@ resistance_move_apply(struct view *view, double *x, double *y) if (rc.window_edge_strength != 0) { /* Find any relevant window edges encountered by this move */ - edges_find_neighbors(&next_edges, view, target, NULL, - check_edge_window, /* use_pending */ false); + edges_find_neighbors(&next_edges, + view, target, NULL, check_edge_window, + /* use_pending */ false, /* ignore_hidden */ true); } /* If any "best" edges were encountered during this move, snap motion */ @@ -143,8 +144,9 @@ resistance_resize_apply(struct view *view, struct wlr_box *new_geom) if (rc.window_edge_strength != 0) { /* Find any relevant window edges encountered by this move */ - edges_find_neighbors(&next_edges, view, *new_geom, NULL, - check_edge_window, /* use_pending */ false); + edges_find_neighbors(&next_edges, + view, *new_geom, NULL, check_edge_window, + /* use_pending */ false, /* ignore_hidden */ true); } /* If any "best" edges were encountered during this move, snap motion */ diff --git a/src/snap.c b/src/snap.c index 1215f0be..0db5d11c 100644 --- a/src/snap.c +++ b/src/snap.c @@ -121,8 +121,9 @@ snap_move_to_edge(struct view *view, enum view_edge direction, struct border next_edges; edges_initialize(&next_edges); - edges_find_neighbors(&next_edges, view, target, - output, check_edge, /* use_pending */ true); + edges_find_neighbors(&next_edges, + view, target, output, check_edge, + /* use_pending */ true, /* ignore_hidden */ false); /* If any "best" edges were encountered, limit motion */ edges_adjust_move_coords(view, next_edges, @@ -196,8 +197,9 @@ snap_grow_to_next_edge(struct view *view, enum view_edge direction, edges_initialize(&next_edges); /* Limit motion to any intervening edge of other views on this output */ - edges_find_neighbors(&next_edges, view, *geo, - output, check_edge, /* use_pending */ true); + edges_find_neighbors(&next_edges, + view, *geo, output, check_edge, + /* use_pending */ true, /* ignore_hidden */ false); edges_adjust_resize_geom(view, next_edges, resize_edges, geo, /* use_pending */ true); } @@ -255,8 +257,9 @@ snap_shrink_to_next_edge(struct view *view, enum view_edge direction, view->output, check_edge, /* use_pending */ true); /* Limit motion to any intervening edge of ther views on this output */ - edges_find_neighbors(&next_edges, view, *geo, - view->output, check_edge, /* use_pending */ true); + edges_find_neighbors(&next_edges, + view, *geo, view->output, check_edge, + /* use_pending */ true, /* ignore_hidden */ false); edges_adjust_resize_geom(view, next_edges, resize_edges, geo, /* use_pending */ true); From d3b0c69ec15bb5d64bbad3ee22ba03c9599c595b Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Fri, 9 Feb 2024 05:12:00 +0100 Subject: [PATCH 02/33] src/debug.c: detect more scene trees Also - resolve workspaces names and view app_id - truncate everything --- src/debug.c | 84 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 66 insertions(+), 18 deletions(-) diff --git a/src/debug.c b/src/debug.c index bac6cbaa..af722f3e 100644 --- a/src/debug.c +++ b/src/debug.c @@ -1,19 +1,23 @@ // SPDX-License-Identifier: GPL-2.0-only #include #include +#include "common/graphic-helpers.h" #include "common/scene-helpers.h" #include "debug.h" #include "labwc.h" #include "node.h" #include "ssd.h" #include "view.h" +#include "workspaces.h" #define HEADER_CHARS "------------------------------" #define INDENT_SIZE 3 +#define LEFT_COL_SPACE 35 + #define IGNORE_SSD true #define IGNORE_MENU true -#define LEFT_COL_SPACE 35 +#define IGNORE_OSD_PREVIEW_OUTLINE true static struct view *last_view; @@ -42,13 +46,13 @@ get_layer_name(uint32_t layer) { switch (layer) { case ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND: - return "layer-background"; + return "output->layer-background"; case ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM: - return "layer-bottom"; + return "output->layer-bottom"; case ZWLR_LAYER_SHELL_V1_LAYER_TOP: - return "layer-top"; + return "output->layer-top"; case ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY: - return "layer-overlay"; + return "output->layer-overlay"; default: abort(); } @@ -57,16 +61,27 @@ get_layer_name(uint32_t layer) static const char * get_view_part(struct view *view, struct wlr_scene_node *node) { - if (view && node == &view->scene_tree->node) { - return "view"; + static char view_name[LEFT_COL_SPACE]; + if (!view) { + return NULL; } - if (view && node == view->scene_node) { + if (node == &view->scene_tree->node) { + const char *app_id = view_get_string_prop(view, "app_id"); + if (!app_id) { + return "view"; + } + snprintf(view_name, sizeof(view_name), "view (%s)", app_id); + return view_name; + } + if (node == view->scene_node) { return "view->scene_node"; } - if (view) { - return ssd_debug_get_node_name(view->ssd, node); + if (view->resize_indicator.tree + && node == &view->resize_indicator.tree->node) { + /* Created on-demand */ + return "view->resize_indicator"; } - return NULL; + return ssd_debug_get_node_name(view->ssd, node); } static const char * @@ -81,12 +96,20 @@ get_special(struct server *server, struct wlr_scene_node *node) if (node == &server->view_tree->node) { return "server->view_tree"; } + if (node == &server->view_tree_always_on_bottom->node) { + return "server->always_on_bottom"; + } if (node == &server->view_tree_always_on_top->node) { - return "server->view_tree_always_on_top"; + return "server->always_on_top"; } if (node->parent == server->view_tree) { - /* Add node_descriptor just to get the name here? */ - return "workspace"; + struct workspace *workspace; + wl_list_for_each(workspace, &server->workspaces, link) { + if (&workspace->tree->node == node) { + return workspace->name; + } + } + return "unknown workspace"; } if (node->parent == &server->scene->tree) { struct output *output; @@ -95,15 +118,34 @@ get_special(struct server *server, struct wlr_scene_node *node) return "output->osd_tree"; } if (node == &output->layer_popup_tree->node) { - return "output->popup_tree"; + return "output->layer_popup_tree"; } for (int i = 0; i < 4; i++) { if (node == &output->layer_tree[i]->node) { return get_layer_name(i); } } + if (node == &output->session_lock_tree->node) { + return "output->session_lock_tree"; + } } } + if (node == &server->xdg_popup_tree->node) { + return "server->xdg_popup_tree"; + } + if (node == &server->seat.drag.icons->node) { + return "seat->drag.icons"; + } + if (server->seat.region_overlay.tree + && node == &server->seat.region_overlay.tree->node) { + /* Created on-demand */ + return "seat->region_overlay"; + } + if (server->osd_state.preview_outline + && node == &server->osd_state.preview_outline->tree->node) { + /* Created on-demand */ + return "osd_state->preview_outline"; + } #if HAVE_XWAYLAND if (node == &server->unmanaged_tree->node) { return "server->unmanaged_tree"; @@ -155,15 +197,21 @@ dump_tree(struct server *server, struct wlr_scene_node *node, HEADER_CHARS, HEADER_CHARS, HEADER_CHARS); printf(" "); } - int padding = LEFT_COL_SPACE - pos - strlen(type); + int max_width = LEFT_COL_SPACE - pos; + int padding = max_width - strlen(type); + if (padding < 0) { + padding = 0; + } if (!pos) { padding += 3; } - printf("%s %*c %4d %4d [%p]\n", type, padding, ' ', x, y, node); + printf("%.*s %*c %4d %4d [%p]\n", max_width - 1, type, padding, ' ', x, y, node); if ((IGNORE_MENU && node == &server->menu_tree->node) || (IGNORE_SSD && last_view - && ssd_debug_is_root_node(last_view->ssd, node))) { + && ssd_debug_is_root_node(last_view->ssd, node)) + || (IGNORE_OSD_PREVIEW_OUTLINE && server->osd_state.preview_outline + && node == &server->osd_state.preview_outline->tree->node)) { printf("%*c%s\n", pos + 4 + INDENT_SIZE, ' ', ""); return; } From 17bad48d87f5550dcdd16a03fd95b9bd9ebc73b3 Mon Sep 17 00:00:00 2001 From: "Andrew J. Hesford" Date: Thu, 1 Feb 2024 16:56:54 -0500 Subject: [PATCH 03/33] edges: better ignore edges of windows not on same output as moving view --- src/edges.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/edges.c b/src/edges.c index b5630a6e..3b507c3e 100644 --- a/src/edges.c +++ b/src/edges.c @@ -383,6 +383,11 @@ edges_find_neighbors(struct border *nearest_edges, struct view *view, assert(validator); assert(nearest_edges); + if (!output_is_usable(view->output)) { + wlr_log(WLR_DEBUG, "ignoring edge search for view on unsable output"); + return; + } + struct border view_edges = { 0 }; struct border target_edges = { 0 }; @@ -406,22 +411,13 @@ edges_find_neighbors(struct border *nearest_edges, struct view *view, continue; } - if (output && v->output != output) { + if (output && output != v->output && !view_on_output(v, output)) { continue; } - /* - * If view and v are on different outputs, make sure part of - * view is actually in the usable area of the output of v. - */ - if (view->output != v->output) { - struct wlr_box usable = - output_usable_area_in_layout_coords(v->output); - - struct wlr_box ol; - if (!wlr_box_intersection(&ol, view_geom, &usable)) { - continue; - } + /* Both view and v must share a common output */ + if (view->output != v->output && !(view->outputs & v->outputs)) { + continue; } struct border border = ssd_get_margin(v->ssd); @@ -448,6 +444,12 @@ edges_find_outputs(struct border *nearest_edges, struct view *view, assert(validator); assert(nearest_edges); + if (!output_is_usable(view->output)) { + wlr_log(WLR_DEBUG, + "ignoring edge search for view on unsable output"); + return; + } + struct border view_edges = { 0 }; struct border target_edges = { 0 }; From 8be9c384602233389f58f1a3d2ab3b4159319b00 Mon Sep 17 00:00:00 2001 From: Marvin Dostal Date: Wed, 21 Feb 2024 18:19:48 +0100 Subject: [PATCH 04/33] Add click method libinput option (#1416) none|buttonAreas|clickfinger --- docs/labwc-config.5.scd | 17 +++++++++++++++++ docs/rc.xml.all | 4 +++- include/config/libinput.h | 1 + src/config/libinput.c | 1 + src/config/rcxml.c | 13 +++++++++++++ src/seat.c | 18 ++++++++++++++++++ 6 files changed, 53 insertions(+), 1 deletion(-) diff --git a/docs/labwc-config.5.scd b/docs/labwc-config.5.scd index 13751813..bc8cf59b 100644 --- a/docs/labwc-config.5.scd +++ b/docs/labwc-config.5.scd @@ -592,6 +592,7 @@ extending outward from the snapped edge. + ``` @@ -667,6 +668,22 @@ extending outward from the snapped edge. any motion events while a keyboard is typing, and for a short while after as well. +** [none|buttonAreas|clickfinger] + Configure the method by which physical clicks on a touchpad are mapped to + mouse-button events. + + The click methods available are: + - *buttonAreas* - The bottom of the touchpad is divided into distinct + regions corresponding to left, middle and right buttons; clicking within + the region will trigger the corresponding event. Clicking the main area + further up produces a left button event. + - *clickfinger* - Clicking with one, two or three finger(s) will produce + left, right or middle button event without regard to the location of a + click. + - *none* - Physical clicks will not produce button events. + + The default method depends on the touchpad hardware. + ## WINDOW RULES Two types of window rules are supported, actions and properties. They are diff --git a/docs/rc.xml.all b/docs/rc.xml.all index 423bcb74..5d0c4cff 100644 --- a/docs/rc.xml.all +++ b/docs/rc.xml.all @@ -465,13 +465,14 @@ non-touch, default or the name of a device. You can obtain device names by running *libinput list-devices* as root or member of the input group. - Tap is set to *yes* be default. All others are left blank in order to use + Tap is set to *yes* by default. All others are left blank in order to use device defaults. All values are [yes|no] except for: - pointerSpeed [-1.0 to 1.0] - accelProfile [flat|adaptive] - tapButtonMap [lrm|lmr] + - clickMethod [none|buttonAreas|clickfinger] --> @@ -485,6 +486,7 @@ + diff --git a/include/config/libinput.h b/include/config/libinput.h index 4ec0ebb7..dffeea98 100644 --- a/include/config/libinput.h +++ b/include/config/libinput.h @@ -28,6 +28,7 @@ struct libinput_category { int accel_profile; /* -1 or libinput_config_accel_profile */ int middle_emu; /* -1 or libinput_config_middle_emulation_state */ int dwt; /* -1 or libinput_config_dwt_state */ + int click_method; /* -1 or libinput_config_click_method */ }; enum lab_libinput_device_type get_device_type(const char *s); diff --git a/src/config/libinput.c b/src/config/libinput.c index 7ce62b79..a8de5e7b 100644 --- a/src/config/libinput.c +++ b/src/config/libinput.c @@ -23,6 +23,7 @@ libinput_category_init(struct libinput_category *l) l->accel_profile = -1; l->middle_emu = -1; l->dwt = -1; + l->click_method = -1; } enum lab_libinput_device_type diff --git a/src/config/rcxml.c b/src/config/rcxml.c index 61784e13..f18cce32 100644 --- a/src/config/rcxml.c +++ b/src/config/rcxml.c @@ -563,6 +563,19 @@ fill_libinput_category(char *nodename, char *content) current_libinput_category->dwt = ret ? LIBINPUT_CONFIG_DWT_ENABLED : LIBINPUT_CONFIG_DWT_DISABLED; + } else if (!strcasecmp(nodename, "clickMethod")) { + if (!strcasecmp(content, "none")) { + current_libinput_category->click_method = + LIBINPUT_CONFIG_CLICK_METHOD_NONE; + } else if (!strcasecmp(content, "clickfinger")) { + current_libinput_category->click_method = + LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER; + } else if (!strcasecmp(content, "buttonAreas")) { + current_libinput_category->click_method = + LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS; + } else { + wlr_log(WLR_ERROR, "invalid clickMethod"); + } } } diff --git a/src/seat.c b/src/seat.c index 52b1b5d0..0f421987 100644 --- a/src/seat.c +++ b/src/seat.c @@ -189,6 +189,24 @@ configure_libinput(struct wlr_input_device *wlr_input_device) wlr_log(WLR_INFO, "dwt configured"); libinput_device_config_dwt_set_enabled(libinput_dev, dc->dwt); } + if ((libinput_device_config_click_get_methods(libinput_dev) + & dc->click_method) == 0 + || dc->click_method < 0) { + wlr_log(WLR_INFO, "click method not configured"); + } else { + wlr_log(WLR_INFO, "click method configured"); + + /* + * Note, the documentation claims that: + * > [...] The device may require changing to a neutral state + * > first before activating the new method. + * + * However, just setting the method seems to work without + * issues. + */ + + libinput_device_config_click_set_method(libinput_dev, dc->click_method); + } } static struct wlr_output * From d00d3ec00ba32c57483eec5b144a8f6011eeda12 Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 21 Feb 2024 15:23:23 +0100 Subject: [PATCH 05/33] Translation updates from weblate Co-authored-by: A S Alam Co-authored-by: Weblate Co-authored-by: winerysearch Translate-URL: https://translate.lxqt-project.org/projects/labwc/labwc/hu/ Translate-URL: https://translate.lxqt-project.org/projects/labwc/labwc/pa/ Translation: Labwc/labwc --- po/LINGUAS | 2 +- po/hu.po | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ po/pa.po | 7 +++--- 3 files changed, 77 insertions(+), 4 deletions(-) create mode 100644 po/hu.po diff --git a/po/LINGUAS b/po/LINGUAS index 58f25cb0..b27cc570 100644 --- a/po/LINGUAS +++ b/po/LINGUAS @@ -1 +1 @@ -de es et eu fi gl id it ja ka lt nl pa pl pt ru sv tr uk zh_CN +de es et eu fi gl hu id it ja ka lt nl pa pl pt ru sv tr uk zh_CN diff --git a/po/hu.po b/po/hu.po new file mode 100644 index 00000000..da861355 --- /dev/null +++ b/po/hu.po @@ -0,0 +1,72 @@ +# Labwc pot file +# Copyright (C) 2024 +# This file is distributed under the same license as the labwc package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: labwc\n" +"Report-Msgid-Bugs-To: https://github.com/labwc/labwc/issues\n" +"POT-Creation-Date: 2024-01-15 16:00-0500\n" +"PO-Revision-Date: 2024-02-19 21:23+0000\n" +"Last-Translator: winerysearch \n" +"Language-Team: Hungarian \n" +"Language: hu\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.2.1\n" + +#: src/menu/menu.c:697 +msgid "Reconfigure" +msgstr "Rekonfigurál" + +#: src/menu/menu.c:699 +msgid "Exit" +msgstr "Kilépés" + +#: src/menu/menu.c:715 +msgid "Minimize" +msgstr "Kis méret" + +#: src/menu/menu.c:717 +msgid "Maximize" +msgstr "Teljes méret" + +#: src/menu/menu.c:719 +msgid "Fullscreen" +msgstr "Teljes képernyő" + +#: src/menu/menu.c:721 +msgid "Roll up/down" +msgstr "Felhúz / Legördül" + +#: src/menu/menu.c:723 +msgid "Decorations" +msgstr "Dekorációk" + +#: src/menu/menu.c:725 +msgid "Always on Top" +msgstr "Mindig felül" + +#: src/menu/menu.c:730 +msgid "Move left" +msgstr "Balra dokkol" + +#: src/menu/menu.c:737 +msgid "Move right" +msgstr "Jobbra dokkol" + +#: src/menu/menu.c:742 +msgid "Always on Visible Workspace" +msgstr "Kitűz" + +#: src/menu/menu.c:745 +msgid "Workspace" +msgstr "Munkaasztal" + +#: src/menu/menu.c:748 +msgid "Close" +msgstr "Bezárás" diff --git a/po/pa.po b/po/pa.po index 77cd6b2c..655a83b1 100644 --- a/po/pa.po +++ b/po/pa.po @@ -8,9 +8,10 @@ msgstr "" "Project-Id-Version: labwc\n" "Report-Msgid-Bugs-To: https://github.com/labwc/labwc/issues\n" "POT-Creation-Date: 2024-01-15 16:00-0500\n" -"PO-Revision-Date: 2023-12-26 07:23+0000\n" +"PO-Revision-Date: 2024-02-21 14:23+0000\n" "Last-Translator: A S Alam \n" -"Language-Team: Punjabi \n" +"Language-Team: Punjabi \n" "Language: pa\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -40,7 +41,7 @@ msgstr "ਪੂਰੀ ਸਕਰੀਨ" #: src/menu/menu.c:721 msgid "Roll up/down" -msgstr "" +msgstr "ਉੱਤੇ/ਹੇਠਾਂ ਸਕਰਾਓ" #: src/menu/menu.c:723 msgid "Decorations" From 1aa906e0de740a6af96c7365e03c137f84bbc414 Mon Sep 17 00:00:00 2001 From: Johan Malm Date: Mon, 19 Feb 2024 22:01:27 +0000 Subject: [PATCH 06/33] README.md: Add screenshot description ...and use the png files on the labwc website rather than imgur. Fixes: #1363 --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f2c4c375..10339da7 100644 --- a/README.md +++ b/README.md @@ -127,8 +127,11 @@ High-level summary of items that Labwc supports: The obligatory screenshot: - - + + +
+ + Screenshot description ## 2. Build and Installation From d69faffc4edcf179396c820eaea0d4d18b30ca1f Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Thu, 22 Feb 2024 21:22:28 +0100 Subject: [PATCH 07/33] src/output.c: notify clients about config errors Preliminary fix for #1525. Based on the protocol we should also revert all previously correctly committed outputs. #1528 is doing just that but may cause regressions so we need a short term solution and then deal with potential issues in #1528 after the release. --- src/output.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/output.c b/src/output.c index 6d05ee94..28ee298f 100644 --- a/src/output.c +++ b/src/output.c @@ -405,10 +405,11 @@ output_update_for_layout_change(struct server *server) cursor_update_image(&server->seat); } -static void +static bool output_config_apply(struct server *server, struct wlr_output_configuration_v1 *config) { + bool success = true; server->pending_output_layout_change++; struct wlr_output_configuration_head_v1 *head; @@ -436,8 +437,15 @@ output_config_apply(struct server *server, output_enable_adaptive_sync(o, head->state.adaptive_sync_enabled); } if (!wlr_output_commit(o)) { - wlr_log(WLR_ERROR, "Output config commit failed"); - continue; + /* + * FIXME: This is only part of the story, we should revert + * all previously commited outputs as well here. + * + * See https://github.com/labwc/labwc/pull/1528 + */ + wlr_log(WLR_INFO, "Output config commit failed: %s", o->name); + success = false; + break; } /* Only do Layout specific actions if the commit went trough */ @@ -477,6 +485,7 @@ output_config_apply(struct server *server, server->pending_output_layout_change--; do_output_layout_change(server); + return success; } static bool @@ -569,8 +578,7 @@ handle_output_manager_apply(struct wl_listener *listener, void *data) bool config_is_good = verify_output_config_v1(config); - if (config_is_good) { - output_config_apply(server, config); + if (config_is_good && output_config_apply(server, config)) { wlr_output_configuration_v1_send_succeeded(config); } else { wlr_output_configuration_v1_send_failed(config); From 7adf5533f975736be1b1a20b25dcaa650b32c0e0 Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Thu, 22 Feb 2024 21:24:05 +0100 Subject: [PATCH 08/33] src/output.c: log when disabling adaptive_sync on a nested labwc --- src/output.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/output.c b/src/output.c index 28ee298f..e1c615e7 100644 --- a/src/output.c +++ b/src/output.c @@ -518,11 +518,17 @@ verify_output_config_v1(const struct wlr_output_configuration_v1 *config) if (wlr_output_is_wl(head->state.output) && refresh != 0) { /* Wayland backend does not support refresh rates */ - err_msg = "Wayland backend refresh rate unsupported"; + err_msg = "Wayland backend refresh rates unsupported"; goto custom_mode_failed; } } + if (wlr_output_is_wl(head->state.output) + && !head->state.adaptive_sync_enabled) { + err_msg = "Wayland backend requires adaptive sync"; + goto custom_mode_failed; + } + /* * Ensure the new output state can be applied on * its own and inform the client when it can not. From 9456b50983e2a90d72c3cb5de80636bed4ce728f Mon Sep 17 00:00:00 2001 From: Jens Peters Date: Sat, 24 Feb 2024 19:12:56 +0100 Subject: [PATCH 09/33] seat: fix configure condition for click method Exclude none (zero) from the bitmask test , otherwise the bitmask test is always true when click method is configured to 'none' and as a result the configuration will be skipped. --- src/seat.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/seat.c b/src/seat.c index 0f421987..635945b1 100644 --- a/src/seat.c +++ b/src/seat.c @@ -189,8 +189,10 @@ configure_libinput(struct wlr_input_device *wlr_input_device) wlr_log(WLR_INFO, "dwt configured"); libinput_device_config_dwt_set_enabled(libinput_dev, dc->dwt); } - if ((libinput_device_config_click_get_methods(libinput_dev) - & dc->click_method) == 0 + + if ((dc->click_method != LIBINPUT_CONFIG_CLICK_METHOD_NONE + && (libinput_device_config_click_get_methods(libinput_dev) + & dc->click_method) == 0) || dc->click_method < 0) { wlr_log(WLR_INFO, "click method not configured"); } else { From 6fb06c54c28c4063a87f189e1fc08c0a0d4d5485 Mon Sep 17 00:00:00 2001 From: Sachin Bhat Date: Mon, 26 Jun 2023 07:36:54 +0800 Subject: [PATCH 10/33] config: support libinput sendEventsMode This allows to enable / disable libinput devices. Co-Authored-By: @Consolatis --- docs/labwc-config.5.scd | 14 ++++++++++++++ docs/rc.xml.all | 2 ++ include/config/libinput.h | 13 +++++++------ src/config/libinput.c | 1 + src/config/rcxml.c | 26 ++++++++++++++++++++++++++ src/seat.c | 28 ++++++++++++++++++++++++++++ 6 files changed, 78 insertions(+), 6 deletions(-) diff --git a/docs/labwc-config.5.scd b/docs/labwc-config.5.scd index bc8cf59b..223eae0a 100644 --- a/docs/labwc-config.5.scd +++ b/docs/labwc-config.5.scd @@ -684,6 +684,20 @@ extending outward from the snapped edge. The default method depends on the touchpad hardware. +** [yes|no|disabledOnExternalMouse] + Optionally enable or disable sending any device events. + + The options available are: + - *yes* - Events are sent as usual + - *no* - No events are sent from this device + - *disabledOnExternalMouse* - This device does not send events if an + external mouse has been detected. + + It is possible to prevent events from a device in the config and then do + a Reconfigure to temporarily enable / disable specific devices. + + By default, this setting is not configured. + ## WINDOW RULES Two types of window rules are supported, actions and properties. They are diff --git a/docs/rc.xml.all b/docs/rc.xml.all index 5d0c4cff..c3586ae0 100644 --- a/docs/rc.xml.all +++ b/docs/rc.xml.all @@ -473,6 +473,7 @@ - accelProfile [flat|adaptive] - tapButtonMap [lrm|lmr] - clickMethod [none|buttonAreas|clickfinger] + - sendEventsMode [yes|no|disabledOnExternalMouse] --> @@ -487,6 +488,7 @@ + diff --git a/include/config/libinput.h b/include/config/libinput.h index dffeea98..912009ea 100644 --- a/include/config/libinput.h +++ b/include/config/libinput.h @@ -23,12 +23,13 @@ struct libinput_category { int left_handed; enum libinput_config_tap_state tap; enum libinput_config_tap_button_map tap_button_map; - int tap_and_drag; /* -1 or libinput_config_drag_state */ - int drag_lock; /* -1 or libinput_config_drag_lock_state */ - int accel_profile; /* -1 or libinput_config_accel_profile */ - int middle_emu; /* -1 or libinput_config_middle_emulation_state */ - int dwt; /* -1 or libinput_config_dwt_state */ - int click_method; /* -1 or libinput_config_click_method */ + int tap_and_drag; /* -1 or libinput_config_drag_state */ + int drag_lock; /* -1 or libinput_config_drag_lock_state */ + int accel_profile; /* -1 or libinput_config_accel_profile */ + int middle_emu; /* -1 or libinput_config_middle_emulation_state */ + int dwt; /* -1 or libinput_config_dwt_state */ + int click_method; /* -1 or libinput_config_click_method */ + int send_events_mode; /* -1 or libinput_config_send_events_mode */ }; enum lab_libinput_device_type get_device_type(const char *s); diff --git a/src/config/libinput.c b/src/config/libinput.c index a8de5e7b..93ab9af2 100644 --- a/src/config/libinput.c +++ b/src/config/libinput.c @@ -24,6 +24,7 @@ libinput_category_init(struct libinput_category *l) l->middle_emu = -1; l->dwt = -1; l->click_method = -1; + l->send_events_mode = -1; } enum lab_libinput_device_type diff --git a/src/config/rcxml.c b/src/config/rcxml.c index f18cce32..56f93e36 100644 --- a/src/config/rcxml.c +++ b/src/config/rcxml.c @@ -461,6 +461,29 @@ get_accel_profile(const char *s) return -1; } +static int +get_send_events_mode(const char *s) +{ + if (!s) { + goto err; + } + + int ret = parse_bool(s, -1); + if (ret >= 0) { + return ret + ? LIBINPUT_CONFIG_SEND_EVENTS_ENABLED + : LIBINPUT_CONFIG_SEND_EVENTS_DISABLED; + } + + if (!strcasecmp(s, "disabledOnExternalMouse")) { + return LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE; + } + +err: + wlr_log(WLR_INFO, "Not a recognised send events mode"); + return -1; +} + static void fill_libinput_category(char *nodename, char *content) { @@ -576,6 +599,9 @@ fill_libinput_category(char *nodename, char *content) } else { wlr_log(WLR_ERROR, "invalid clickMethod"); } + } else if (!strcasecmp(nodename, "sendEventsMode")) { + current_libinput_category->send_events_mode = + get_send_events_mode(content); } } diff --git a/src/seat.c b/src/seat.c index 635945b1..e4e69efe 100644 --- a/src/seat.c +++ b/src/seat.c @@ -91,6 +91,24 @@ get_category(struct wlr_input_device *device) static void configure_libinput(struct wlr_input_device *wlr_input_device) { + /* + * TODO: We do not check any return values for the various + * libinput_device_config_*_set_*() calls. It would + * be nice if we could inform the users via log file + * that some libinput setting could not be applied. + * + * TODO: We are currently using int32_t with -1 as default + * to desribe the not-configured state. This is not + * really optimal as we can't properly deal with + * enum values that are 0. After some discussion via + * IRC the best way forward seem to be to use a + * uint32_t instead and UINT32_MAX as indicator for + * a not-configured state. This allows to properly + * test the enum being a member of a bitset via + * mask & value == value. All libinput enums are + * way below UINT32_MAX. + */ + if (!wlr_input_device) { wlr_log(WLR_ERROR, "no wlr_input_device"); return; @@ -209,6 +227,16 @@ configure_libinput(struct wlr_input_device *wlr_input_device) libinput_device_config_click_set_method(libinput_dev, dc->click_method); } + + if ((dc->send_events_mode != LIBINPUT_CONFIG_SEND_EVENTS_ENABLED + && (libinput_device_config_send_events_get_modes(libinput_dev) + & dc->send_events_mode) == 0) + || dc->send_events_mode < 0) { + wlr_log(WLR_INFO, "send events mode not configured"); + } else { + wlr_log(WLR_INFO, "send events mode configured"); + libinput_device_config_send_events_set_mode(libinput_dev, dc->send_events_mode); + } } static struct wlr_output * From fb1a0a2bdf9aa8ddec782b4a51b219ab54b2a0b6 Mon Sep 17 00:00:00 2001 From: Weblate Date: Sat, 24 Feb 2024 23:23:23 +0100 Subject: [PATCH 11/33] Translation updates from weblate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sabri Ünal Translate-URL: https://translate.lxqt-project.org/projects/labwc/labwc/tr/ Translation: Labwc/labwc --- po/tr.po | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/po/tr.po b/po/tr.po index 64ad85f6..20505905 100644 --- a/po/tr.po +++ b/po/tr.po @@ -8,9 +8,10 @@ msgstr "" "Project-Id-Version: labwc\n" "Report-Msgid-Bugs-To: https://github.com/labwc/labwc/issues\n" "POT-Creation-Date: 2024-01-15 16:00-0500\n" -"PO-Revision-Date: 2023-12-26 09:00+0000\n" +"PO-Revision-Date: 2024-02-24 22:23+0000\n" "Last-Translator: Sabri Ünal \n" -"Language-Team: Turkish \n" +"Language-Team: Turkish \n" "Language: tr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -40,7 +41,7 @@ msgstr "Tam Ekran" #: src/menu/menu.c:721 msgid "Roll up/down" -msgstr "" +msgstr "Yukarı/aşağı katla" #: src/menu/menu.c:723 msgid "Decorations" From 598ab9bcff4ea9f3a152b75d3e824b2c6bcb7dc9 Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Sat, 24 Feb 2024 23:05:02 +0100 Subject: [PATCH 12/33] src/layers.c: delay popup unconstrain until after first commit Fixes: #1372 --- include/layers.h | 1 + src/layers.c | 36 +++++++++++++++++++++++++++++------- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/include/layers.h b/include/layers.h index d64c434f..52583035 100644 --- a/include/layers.h +++ b/include/layers.h @@ -28,6 +28,7 @@ struct lab_layer_popup { /* To simplify moving popup nodes from the bottom to the top layer */ struct wlr_box output_toplevel_sx_box; + struct wl_listener commit; struct wl_listener destroy; struct wl_listener new_popup; }; diff --git a/src/layers.c b/src/layers.c index 79cffe94..20e9e683 100644 --- a/src/layers.c +++ b/src/layers.c @@ -260,14 +260,35 @@ popup_handle_destroy(struct wl_listener *listener, void *data) wl_container_of(listener, popup, destroy); wl_list_remove(&popup->destroy.link); wl_list_remove(&popup->new_popup.link); + + /* Usually already removed unless there was no commit at all */ + if (popup->commit.notify) { + wl_list_remove(&popup->commit.link); + } + free(popup); } +static void +popup_handle_commit(struct wl_listener *listener, void *data) +{ + struct lab_layer_popup *popup = + wl_container_of(listener, popup, commit); + + if (popup->wlr_popup->base->initial_commit) { + wlr_xdg_popup_unconstrain_from_box(popup->wlr_popup, + &popup->output_toplevel_sx_box); + + /* Prevent getting called over and over again */ + wl_list_remove(&popup->commit.link); + popup->commit.notify = NULL; + } +} + 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) +create_popup(struct wlr_xdg_popup *wlr_popup, struct wlr_scene_tree *parent) { struct lab_layer_popup *popup = znew(*popup); popup->wlr_popup = wlr_popup; @@ -282,10 +303,13 @@ create_popup(struct wlr_xdg_popup *wlr_popup, struct wlr_scene_tree *parent, 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); + popup->commit.notify = popup_handle_commit; + wl_signal_add(&wlr_popup->base->surface->events.commit, &popup->commit); + return popup; } @@ -297,8 +321,7 @@ popup_handle_new_popup(struct wl_listener *listener, void *data) 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); + lab_layer_popup->scene_tree); new_popup->output_toplevel_sx_box = lab_layer_popup->output_toplevel_sx_box; } @@ -357,8 +380,7 @@ handle_new_popup(struct wl_listener *listener, void *data) .width = output_box.width, .height = output_box.height, }; - struct lab_layer_popup *popup = create_popup(wlr_popup, - surface->tree, &output_toplevel_sx_box); + struct lab_layer_popup *popup = create_popup(wlr_popup, surface->tree); popup->output_toplevel_sx_box = output_toplevel_sx_box; if (surface->layer_surface->current.layer From ccbc75571a8d1e8fbae477db1b3401eb031ed335 Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Sat, 24 Feb 2024 23:16:55 +0100 Subject: [PATCH 13/33] src/xdg-popup.c: delay popup unconstrain until after first commit Fixes: #1372 --- src/xdg-popup.c | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/src/xdg-popup.c b/src/xdg-popup.c index 496c5c0c..65c13e8d 100644 --- a/src/xdg-popup.c +++ b/src/xdg-popup.c @@ -16,15 +16,17 @@ struct xdg_popup { struct view *parent_view; struct wlr_xdg_popup *wlr_popup; + struct wl_listener commit; struct wl_listener destroy; struct wl_listener new_popup; }; static void -popup_unconstrain(struct view *view, struct wlr_xdg_popup *popup) +popup_unconstrain(struct xdg_popup *popup) { + struct view *view = popup->parent_view; struct server *server = view->server; - struct wlr_box *popup_box = &popup->current.geometry; + struct wlr_box *popup_box = &popup->wlr_popup->current.geometry; struct wlr_output_layout *output_layout = server->output_layout; struct wlr_output *wlr_output = wlr_output_layout_output_at( output_layout, view->current.x + popup_box->x, @@ -39,7 +41,7 @@ popup_unconstrain(struct view *view, struct wlr_xdg_popup *popup) .width = output_box.width, .height = output_box.height, }; - wlr_xdg_popup_unconstrain_from_box(popup, &output_toplevel_box); + wlr_xdg_popup_unconstrain_from_box(popup->wlr_popup, &output_toplevel_box); } static void @@ -48,9 +50,28 @@ handle_xdg_popup_destroy(struct wl_listener *listener, void *data) struct xdg_popup *popup = wl_container_of(listener, popup, destroy); wl_list_remove(&popup->destroy.link); wl_list_remove(&popup->new_popup.link); + + /* Usually already removed unless there was no commit at all */ + if (popup->commit.notify) { + wl_list_remove(&popup->commit.link); + } free(popup); } +static void +handle_xdg_popup_commit(struct wl_listener *listener, void *data) +{ + struct xdg_popup *popup = wl_container_of(listener, popup, commit); + + if (popup->wlr_popup->base->initial_commit) { + popup_unconstrain(popup); + + /* Prevent getting called over and over again */ + wl_list_remove(&popup->commit.link); + popup->commit.notify = NULL; + } +} + static void popup_handle_new_xdg_popup(struct wl_listener *listener, void *data) { @@ -75,9 +96,13 @@ xdg_popup_create(struct view *view, struct wlr_xdg_popup *wlr_popup) popup->destroy.notify = handle_xdg_popup_destroy; wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy); + popup->new_popup.notify = popup_handle_new_xdg_popup; wl_signal_add(&wlr_popup->base->events.new_popup, &popup->new_popup); + popup->commit.notify = handle_xdg_popup_commit; + wl_signal_add(&wlr_popup->base->surface->events.commit, &popup->commit); + /* * We must add xdg popups to the scene graph so they get rendered. The * wlroots scene graph provides a helper for this, but to use it we must @@ -100,6 +125,4 @@ xdg_popup_create(struct view *view, struct wlr_xdg_popup *wlr_popup) wlr_scene_xdg_surface_create(parent_tree, wlr_popup->base); node_descriptor_create(wlr_popup->base->surface->data, LAB_NODE_DESC_XDG_POPUP, view); - - popup_unconstrain(view, wlr_popup); } From 7110b7cf3e4146240c1651c4218230ad46b32856 Mon Sep 17 00:00:00 2001 From: Jens Peters Date: Sun, 25 Feb 2024 20:31:16 +0100 Subject: [PATCH 14/33] docs: add sendEventsMode to libinput snippet --- docs/labwc-config.5.scd | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/labwc-config.5.scd b/docs/labwc-config.5.scd index 223eae0a..e634a27c 100644 --- a/docs/labwc-config.5.scd +++ b/docs/labwc-config.5.scd @@ -593,6 +593,7 @@ extending outward from the snapped edge. + ``` From d3c5b0ebb8125001f16211c7bbcdebeeac3596eb Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Wed, 28 Feb 2024 19:28:51 +0100 Subject: [PATCH 15/33] CONTRIBUTING.md: Void maintainer nick change --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 33cb225e..1a5b41fa 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -98,7 +98,7 @@ Some distributions carry labwc in their repositories or user repositories. - @adcdam (Slackware) - @bdantas (Tiny Core Linux) - @Visone-Selektah (Venom Linux) -- @tranzystorek-io (Void Linux) +- @tranzystorekk (Void Linux) kindly maintain the packages in their respective distro. From 43e29f1f8d66bb5c14a2fc57402da69ec6d849ef Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Wed, 28 Feb 2024 21:37:04 +0100 Subject: [PATCH 16/33] docs/rc.xml: remove gap from the example config Some distro packages install the example config at /etc/xdg/labwc/rc.xml and thus users of those packages were having a gap 10 setting by default. Lets remove the gap from the example config to match our intended default. --- docs/rc.xml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/rc.xml b/docs/rc.xml index 3bf2d116..edcca868 100644 --- a/docs/rc.xml +++ b/docs/rc.xml @@ -7,10 +7,6 @@ - - 10 - - 8 From 9b47a5e11ebc88624fbfdb9c889cbae78cfbb0e5 Mon Sep 17 00:00:00 2001 From: Weblate Date: Thu, 29 Feb 2024 15:23:25 +0100 Subject: [PATCH 17/33] Translation updates from weblate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Alice Ventus Co-authored-by: Jouni Järvinen Co-authored-by: Moo Co-authored-by: Weblate Translate-URL: https://translate.lxqt-project.org/projects/labwc/labwc/fi/ Translate-URL: https://translate.lxqt-project.org/projects/labwc/labwc/lt/ Translate-URL: https://translate.lxqt-project.org/projects/labwc/labwc/ru/ Translation: Labwc/labwc --- po/fi.po | 11 +++++++---- po/lt.po | 11 +++++++---- po/ru.po | 5 ++--- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/po/fi.po b/po/fi.po index d67d0355..b5021b65 100644 --- a/po/fi.po +++ b/po/fi.po @@ -8,13 +8,16 @@ msgstr "" "Project-Id-Version: labwc\n" "Report-Msgid-Bugs-To: https://github.com/labwc/labwc/issues\n" "POT-Creation-Date: 2024-01-15 16:00-0500\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Automatically generated\n" -"Language-Team: none\n" +"PO-Revision-Date: 2024-02-29 14:23+0000\n" +"Last-Translator: Jouni Järvinen \n" +"Language-Team: Finnish \n" "Language: fi\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.2.1\n" #: src/menu/menu.c:697 msgid "Reconfigure" @@ -22,7 +25,7 @@ msgstr "" #: src/menu/menu.c:699 msgid "Exit" -msgstr "" +msgstr "Poistu" #: src/menu/menu.c:715 msgid "Minimize" diff --git a/po/lt.po b/po/lt.po index 65ab1166..7ac63f85 100644 --- a/po/lt.po +++ b/po/lt.po @@ -8,14 +8,17 @@ msgstr "" "Project-Id-Version: labwc\n" "Report-Msgid-Bugs-To: https://github.com/labwc/labwc/issues\n" "POT-Creation-Date: 2024-01-15 16:00-0500\n" -"PO-Revision-Date: 2024-01-04 15:23+0000\n" +"PO-Revision-Date: 2024-02-29 14:23+0000\n" "Last-Translator: Moo \n" -"Language-Team: Lithuanian \n" +"Language-Team: Lithuanian \n" "Language: lt\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n % 10 == 1 && (n % 100 < 11 || n % 100 > 19)) ? 0 : ((n % 10 >= 2 && n % 10 <= 9 && (n % 100 < 11 || n % 100 > 19)) ? 1 : 2);\n" +"Plural-Forms: nplurals=3; plural=(n % 10 == 1 && (n % 100 < 11 || n % 100 > " +"19)) ? 0 : ((n % 10 >= 2 && n % 10 <= 9 && (n % 100 < 11 || n % 100 > 19)) ? " +"1 : 2);\n" "X-Generator: Weblate 4.2.1\n" #: src/menu/menu.c:697 @@ -40,7 +43,7 @@ msgstr "Visas ekranas" #: src/menu/menu.c:721 msgid "Roll up/down" -msgstr "" +msgstr "Užraityti/atraityti" #: src/menu/menu.c:723 msgid "Decorations" diff --git a/po/ru.po b/po/ru.po index f9e34051..be979099 100644 --- a/po/ru.po +++ b/po/ru.po @@ -8,8 +8,8 @@ msgstr "" "Project-Id-Version: labwc\n" "Report-Msgid-Bugs-To: https://github.com/labwc/labwc/issues\n" "POT-Creation-Date: 2024-01-15 16:00-0500\n" -"PO-Revision-Date: 2024-01-30 08:23+0000\n" -"Last-Translator: pixis1 \n" +"PO-Revision-Date: 2024-02-26 12:23+0000\n" +"Last-Translator: Alice Ventus \n" "Language-Team: Russian \n" "Language: ru\n" @@ -41,7 +41,6 @@ msgid "Fullscreen" msgstr "На весь экран" #: src/menu/menu.c:721 -#, fuzzy msgid "Roll up/down" msgstr "Свернуть/развернуть в заголовок" From e7345199909138ed43dbe64f10bd25c19272a60d Mon Sep 17 00:00:00 2001 From: Johan Malm Date: Fri, 2 Feb 2024 20:55:16 +0000 Subject: [PATCH 18/33] NEWS.md: update for 0.7.1 --- NEWS.md | 40 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/NEWS.md b/NEWS.md index 11c0cebd..dbafc05f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -9,7 +9,7 @@ The format is based on [Keep a Changelog] | Date | All Changes | wlroots version | lines-of-code | |------------|---------------|-----------------|---------------| -| 2024-01-23 | [unreleased] | 0.17.1 | | +| 2024-03-01 | [0.7.1] | 0.17.1 | 18624 | | 2023-12-22 | [0.7.0] | 0.17.1 | 16576 | | 2023-11-25 | [0.6.6] | 0.16.2 | 15796 | | 2023-09-23 | [0.6.5] | 0.16.2 | 14809 | @@ -28,10 +28,33 @@ The format is based on [Keep a Changelog] | 2021-03-05 | [0.1.0] | 0.12.0 | 4627 | -## [unreleased] +## [0.7.1] ### Added +- Support libinput option sendEventsMode to allow enabling/disabling devices. + Co-Authored-By: @Sachin-Bhat + +```xml + + + yes|no|disabledOnExternalMouse + + +``` + +- Add click method libinput option. Written-by: @datMaffin + +```xml + + + none|buttonAreas|clickfinger + + +``` + +- Add `data/labwc.svg` & `data/labwc-symbolic.svg`, and specify icon name + in labwc.desktop to enable Display Managers to show an icons for labwc. - Expose output configuration test to clients. For example, this enables `wlr-randr --dryrun` - Add window-edge resistance for interactive moves/resizes and support negative @@ -90,6 +113,7 @@ The format is based on [Keep a Changelog] - Add config option `` with supported values `center`, `cursor` and `automatic`. The latter minimizes overlap with other windows already on screen and is similar to Openbox's smart window placement. + The placement policies honour ``. Written-by: @ahesford #1312 ```xml @@ -100,6 +124,13 @@ The format is based on [Keep a Changelog] ### Fixed +- Delay popup-unconstrain until after first commit in response to a changed + wlroots 0.17 interface and to get rid of the error message below. Issue #1372 + + [types/xdg_shell/wlr_xdg_surface.c:169] A configure is scheduled for an uninitialized xdg_surface + +- Notify clients about configuration errors when changing output settings. + Issue #1528. - Fix output configuration bug causing compositor crash when refresh rate is zero. Issue #1458 - Fix disappearing cursor bug on view destruction. Issue #1393 @@ -124,6 +155,8 @@ The format is based on [Keep a Changelog] ### Changed +- Make `MoveToCursor` honour ``. Issue #1494 +- Add `Roll Up/Down` client-menu entry for `ToggleShade` - When a Wayland-native window is snapped to a screen edges or user-defined region, labwc will notify the application that it is "tiled", allowing the application to better adapt its rendering to constrained layouts. Windows @@ -1043,7 +1076,8 @@ Compile with wlroots 0.12.0 and wayland-server >=1.16 ShowMenu [Keep a Changelog]: https://keepachangelog.com/en/1.0.0/ -[unreleased]: https://github.com/labwc/labwc/compare/0.7.0...HEAD +[unreleased]: https://github.com/labwc/labwc/compare/0.7.1...HEAD +[0.7.1]: https://github.com/labwc/labwc/compare/0.7.0...0.7.1 [0.7.0]: https://github.com/labwc/labwc/compare/0.6.6...0.7.0 [0.6.6]: https://github.com/labwc/labwc/compare/0.6.5...0.6.6 [0.6.5]: https://github.com/labwc/labwc/compare/0.6.4...0.6.5 From 59014e507175971e84af2b846b6b3a2c232cce7f Mon Sep 17 00:00:00 2001 From: Johan Malm Date: Fri, 1 Mar 2024 21:16:21 +0000 Subject: [PATCH 19/33] build: bump version to 0.7.1 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index a0a43263..adbd5455 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'labwc', 'c', - version: '0.7.0', + version: '0.7.1', license: 'GPL-2.0-only', meson_version: '>=0.59.0', default_options: [ From 5a70027e3075e63280d087676575d6f19b33d390 Mon Sep 17 00:00:00 2001 From: zenobit Date: Sat, 2 Mar 2024 01:01:22 +0100 Subject: [PATCH 20/33] Add cs language --- po/LINGUAS | 2 +- po/cs.po | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 po/cs.po diff --git a/po/LINGUAS b/po/LINGUAS index b27cc570..1b2407b5 100644 --- a/po/LINGUAS +++ b/po/LINGUAS @@ -1 +1 @@ -de es et eu fi gl hu id it ja ka lt nl pa pl pt ru sv tr uk zh_CN +cs de es et eu fi gl hu id it ja ka lt nl pa pl pt ru sv tr uk zh_CN diff --git a/po/cs.po b/po/cs.po new file mode 100644 index 00000000..104e5012 --- /dev/null +++ b/po/cs.po @@ -0,0 +1,69 @@ +# Labwc pot file +# Copyright (C) 2024 +# This file is distributed under the same license as the labwc package. +# zenobit , 2024. +# +msgid "" +msgstr "" +"Project-Id-Version: labwc\n" +"Report-Msgid-Bugs-To: https://github.com/labwc/labwc/issues\n" +"POT-Creation-Date: 2024-01-15 16:00-0500\n" +"PO-Revision-Date: 2024-03-02 02:00+0100\n" +"Last-Translator: zenobit \n" +"Language-Team: Czech \n" +"Language: cs\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: src/menu/menu.c:697 +msgid "Reconfigure" +msgstr "Překonfigurovat" + +#: src/menu/menu.c:699 +msgid "Exit" +msgstr "Odejít" + +#: src/menu/menu.c:715 +msgid "Minimize" +msgstr "Minimalizovat" + +#: src/menu/menu.c:717 +msgid "Maximize" +msgstr "Maximalizovat" + +#: src/menu/menu.c:719 +msgid "Fullscreen" +msgstr "Na celou obrazovku" + +#: src/menu/menu.c:721 +msgid "Roll up/down" +msgstr "Rolovat nahoru/dolů" + +#: src/menu/menu.c:723 +msgid "Decorations" +msgstr "Dekorace" + +#: src/menu/menu.c:725 +msgid "Always on Top" +msgstr "Vždy nahoře" + +#: src/menu/menu.c:730 +msgid "Move left" +msgstr "Posunout doleva" + +#: src/menu/menu.c:737 +msgid "Move right" +msgstr "Posunout doprava" + +#: src/menu/menu.c:742 +msgid "Always on Visible Workspace" +msgstr "Vždy na viditelné Pracovní Ploše" + +#: src/menu/menu.c:745 +msgid "Workspace" +msgstr "Pracovní Plocha" + +#: src/menu/menu.c:748 +msgid "Close" +msgstr "Zavřít" From 5b2b1c31ab483349b5baa272fdbb08fe2c580972 Mon Sep 17 00:00:00 2001 From: 01micko <01micko#gmail.com> Date: Sat, 2 Mar 2024 11:39:36 +1000 Subject: [PATCH 21/33] CONTRIBUTING.md: correct the instructions for adding a locale code --- CONTRIBUTING.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1a5b41fa..ef6ca30a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -354,10 +354,10 @@ Translators can add their `MY_LOCALE.po` files to the `po` directory based on `po/labwc.pot` and issue a pull request. To do this they can generate their `MY_LOCALE.po` file in a few steps: -1. Edit the `po/LINGUAS` file to add their locale name by adding a space - to the end of the field and typing the locale code. -2. Copy the po/labwc.pot to po/MY_LOCALE.po -3. Edit the newly generated MY_LOCALE.po file with some of their +1. Edit the `po/LINGUAS` file to add their locale code in English + alphabetical order to the field of locale codes. +2. Copy the `po/labwc.pot` to `po/MY_LOCALE.po` +3. Edit the newly generated `MY_LOCALE.po` file with some of their contact and locale details in the header of the file then add the translation strings under each English string. From 1ea7e8b4944d56d21e08d409212e07a15c5f5c09 Mon Sep 17 00:00:00 2001 From: Birger Schacht <1143280+b1rger@users.noreply.github.com> Date: Sat, 2 Mar 2024 08:41:13 +0100 Subject: [PATCH 22/33] fix: typo in labwc-config.5.scd specifc -> specific --- docs/labwc-config.5.scd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/labwc-config.5.scd b/docs/labwc-config.5.scd index e634a27c..ec887f72 100644 --- a/docs/labwc-config.5.scd +++ b/docs/labwc-config.5.scd @@ -511,7 +511,7 @@ extending outward from the snapped edge. ``` ** - A touch configuration can be bound to a specifc device. If device + A touch configuration can be bound to a specific device. If device name is left empty, the touch configuration applies to all touch devices or functions as a fallback. Multiple touch configurations can exist. From 7e338fc365d49f7ffb6bbb3050a142d05f373b59 Mon Sep 17 00:00:00 2001 From: Johan Malm Date: Sat, 2 Mar 2024 15:34:52 +0000 Subject: [PATCH 23/33] view: fix view_get_adjacent_output() bug ...when using more than two outputs. Use the centre of the view's output as the reference coordinate when seeking adjacent outputs. Fixes: #1582 --- src/view.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/view.c b/src/view.c index 87b29e00..e297b725 100644 --- a/src/view.c +++ b/src/view.c @@ -1530,6 +1530,10 @@ view_get_adjacent_output(struct view *view, enum view_edge edge) return NULL; } + struct wlr_box box = output_usable_area_in_layout_coords(view->output); + int lx = box.x + box.width / 2; + int ly = box.y + box.height / 2; + /* Determine any adjacent output in the appropriate direction */ struct wlr_output *new_output = NULL; struct wlr_output *current_output = output->wlr_output; @@ -1537,19 +1541,19 @@ view_get_adjacent_output(struct view *view, enum view_edge edge) switch (edge) { case VIEW_EDGE_LEFT: new_output = wlr_output_layout_adjacent_output( - layout, WLR_DIRECTION_LEFT, current_output, 1, 0); + layout, WLR_DIRECTION_LEFT, current_output, lx, ly); break; case VIEW_EDGE_RIGHT: new_output = wlr_output_layout_adjacent_output( - layout, WLR_DIRECTION_RIGHT, current_output, 1, 0); + layout, WLR_DIRECTION_RIGHT, current_output, lx, ly); break; case VIEW_EDGE_UP: new_output = wlr_output_layout_adjacent_output( - layout, WLR_DIRECTION_UP, current_output, 0, 1); + layout, WLR_DIRECTION_UP, current_output, lx, ly); break; case VIEW_EDGE_DOWN: new_output = wlr_output_layout_adjacent_output( - layout, WLR_DIRECTION_DOWN, current_output, 0, 1); + layout, WLR_DIRECTION_DOWN, current_output, lx, ly); break; default: break; From 3c3bcc2765aa06c9fcf1e7e65862628de1ad33d1 Mon Sep 17 00:00:00 2001 From: Johan Malm Date: Sat, 2 Mar 2024 15:42:05 +0000 Subject: [PATCH 24/33] view: add MoveToOutput `wrap` attribute Support `wrap` in view_get_adjacent_output(). This means that when seeking an adjacent output in a particular direction from an output that is already furthest in that direction within the layout, rather than returning NULL, wrap around from the leftmost to the rightmost, or topmost to the bottommost and vice versa. Example usage: Wrap is disabled by default to keep the user interface consistent. --- docs/labwc-actions.5.scd | 5 ++- include/view.h | 3 +- src/action.c | 7 +++- src/view.c | 81 ++++++++++++++++++++++++++++------------ 4 files changed, 69 insertions(+), 27 deletions(-) diff --git a/docs/labwc-actions.5.scd b/docs/labwc-actions.5.scd index 9d55f63f..facb2d68 100644 --- a/docs/labwc-actions.5.scd +++ b/docs/labwc-actions.5.scd @@ -163,7 +163,7 @@ Actions are used in menus and keyboard/mouse bindings. to the center of the window. If the given output does not contain any windows, the cursor is centered on the given output. -** +** Moves active window to other output, unless the window state is fullscreen. @@ -172,6 +172,9 @@ Actions are used in menus and keyboard/mouse bindings. be one of "left", "right", "up" or "down" to indicate that the window should be moved to the next output in that direction (if one exists). + *wrap* [yes|no] When using the direction attribute, wrap around from + right-to-left or top-to-bottom, and vice versa. Default no. + ** Resizes active window size to width and height of the output when the window size exceeds the output size. diff --git a/include/view.h b/include/view.h index c24fa3d3..b0cb8471 100644 --- a/include/view.h +++ b/include/view.h @@ -503,7 +503,8 @@ void view_on_output_destroy(struct view *view); void view_connect_map(struct view *view, struct wlr_surface *surface); void view_destroy(struct view *view); -struct output *view_get_adjacent_output(struct view *view, enum view_edge edge); +struct output *view_get_adjacent_output(struct view *view, enum view_edge edge, + bool wrap); enum view_axis view_axis_parse(const char *direction); enum view_edge view_edge_parse(const char *direction); diff --git a/src/action.c b/src/action.c index e1187906..953f62e7 100644 --- a/src/action.c +++ b/src/action.c @@ -397,6 +397,10 @@ action_arg_from_xml_node(struct action *action, const char *nodename, const char } goto cleanup; } + if (!strcmp(argument, "wrap")) { + action_arg_add_bool(action, argument, parse_bool(content, false)); + goto cleanup; + } break; case ACTION_TYPE_VIRTUAL_OUTPUT_ADD: case ACTION_TYPE_VIRTUAL_OUTPUT_REMOVE: @@ -924,7 +928,8 @@ actions_run(struct view *activator, struct server *server, } else { /* Config parsing makes sure that direction is a valid direction */ enum view_edge edge = action_get_int(action, "direction", 0); - target = view_get_adjacent_output(view, edge); + bool wrap = action_get_bool(action, "wrap", false); + target = view_get_adjacent_output(view, edge, wrap); } if (!target) { wlr_log(WLR_ERROR, "Invalid output."); diff --git a/src/view.c b/src/view.c index e297b725..52627643 100644 --- a/src/view.c +++ b/src/view.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "common/macros.h" #include "common/match.h" #include "common/mem.h" @@ -1519,8 +1520,44 @@ view_on_output_destroy(struct view *view) view->output = NULL; } +static enum wlr_direction +opposite_direction(enum wlr_direction direction) +{ + switch (direction) { + case WLR_DIRECTION_RIGHT: + return WLR_DIRECTION_LEFT; + case WLR_DIRECTION_LEFT: + return WLR_DIRECTION_RIGHT; + case WLR_DIRECTION_DOWN: + return WLR_DIRECTION_UP; + case WLR_DIRECTION_UP: + return WLR_DIRECTION_DOWN; + default: + return 0; + } +} + +static enum wlr_direction +get_wlr_direction(enum view_edge edge) +{ + switch (edge) { + case VIEW_EDGE_LEFT: + return WLR_DIRECTION_LEFT; + case VIEW_EDGE_RIGHT: + return WLR_DIRECTION_RIGHT; + case VIEW_EDGE_UP: + return WLR_DIRECTION_UP; + case VIEW_EDGE_DOWN: + return WLR_DIRECTION_DOWN; + case VIEW_EDGE_CENTER: + case VIEW_EDGE_INVALID: + default: + return 0; + } +} + struct output * -view_get_adjacent_output(struct view *view, enum view_edge edge) +view_get_adjacent_output(struct view *view, enum view_edge edge, bool wrap) { assert(view); struct output *output = view->output; @@ -1530,7 +1567,7 @@ view_get_adjacent_output(struct view *view, enum view_edge edge) return NULL; } - struct wlr_box box = output_usable_area_in_layout_coords(view->output); + struct wlr_box box = output_usable_area_in_layout_coords(output); int lx = box.x + box.width / 2; int ly = box.y + box.height / 2; @@ -1538,28 +1575,23 @@ view_get_adjacent_output(struct view *view, enum view_edge edge) struct wlr_output *new_output = NULL; struct wlr_output *current_output = output->wlr_output; struct wlr_output_layout *layout = view->server->output_layout; - switch (edge) { - case VIEW_EDGE_LEFT: - new_output = wlr_output_layout_adjacent_output( - layout, WLR_DIRECTION_LEFT, current_output, lx, ly); - break; - case VIEW_EDGE_RIGHT: - new_output = wlr_output_layout_adjacent_output( - layout, WLR_DIRECTION_RIGHT, current_output, lx, ly); - break; - case VIEW_EDGE_UP: - new_output = wlr_output_layout_adjacent_output( - layout, WLR_DIRECTION_UP, current_output, lx, ly); - break; - case VIEW_EDGE_DOWN: - new_output = wlr_output_layout_adjacent_output( - layout, WLR_DIRECTION_DOWN, current_output, lx, ly); - break; - default: - break; + enum wlr_direction direction = get_wlr_direction(edge); + new_output = wlr_output_layout_adjacent_output(layout, direction, + current_output, lx, ly); + + /* + * Optionally wrap around from top-to-bottom or left-to-right, and vice + * versa. + */ + if (wrap && !new_output) { + new_output = wlr_output_layout_farthest_output(layout, + opposite_direction(direction), current_output, lx, ly); } - /* When "adjacent" output is the same as the original, there is no adjacent */ + /* + * When "adjacent" output is the same as the original, there is no + * adjacent + */ if (!new_output || new_output == current_output) { return NULL; } @@ -1633,7 +1665,8 @@ view_move_to_edge(struct view *view, enum view_edge direction, bool snap_to_wind } /* Otherwise, move to edge of next adjacent display, if possible */ - struct output *output = view_get_adjacent_output(view, direction); + struct output *output = + view_get_adjacent_output(view, direction, /* wrap */ false); if (!output) { return; } @@ -1792,7 +1825,7 @@ view_snap_to_edge(struct view *view, enum view_edge edge, if (across_outputs && view->tiled == edge && view->maximized == VIEW_AXIS_NONE) { /* We are already tiled for this edge; try to switch outputs */ - output = view_get_adjacent_output(view, edge); + output = view_get_adjacent_output(view, edge, /* wrap */ false); if (!output) { /* From 4ddeb3cd4224628c0a48fec5edc72b64a1ba08d7 Mon Sep 17 00:00:00 2001 From: Johan Malm Date: Sat, 2 Mar 2024 19:40:33 +0000 Subject: [PATCH 25/33] action: reduce MoveToOutput logging --- src/action.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/action.c b/src/action.c index 953f62e7..1cf8960a 100644 --- a/src/action.c +++ b/src/action.c @@ -932,7 +932,11 @@ actions_run(struct view *activator, struct server *server, target = view_get_adjacent_output(view, edge, wrap); } if (!target) { - wlr_log(WLR_ERROR, "Invalid output."); + /* + * Most likely because we're already on the + * output furthest in the requested direction. + */ + wlr_log(WLR_DEBUG, "Invalid output"); break; } view_move_to_output(view, target); From f90b7dca2a3e862ca64ced14165181c70938b6d7 Mon Sep 17 00:00:00 2001 From: "Andrew J. Hesford" Date: Sun, 18 Feb 2024 12:23:14 -0500 Subject: [PATCH 26/33] session: run shutdown script, clean up activation env before exit --- docs/labwc-config.5.scd | 23 ++++++++--- include/common/string-helpers.h | 19 +++++++++ include/config/session.h | 6 +++ src/common/string-helpers.c | 71 +++++++++++++++++++++++++++++++++ src/config/session.c | 52 +++++++++++++++++++----- src/main.c | 2 + 6 files changed, 157 insertions(+), 16 deletions(-) diff --git a/docs/labwc-config.5.scd b/docs/labwc-config.5.scd index ec887f72..57e76bdc 100644 --- a/docs/labwc-config.5.scd +++ b/docs/labwc-config.5.scd @@ -8,7 +8,7 @@ labwc - configuration files Labwc uses openbox-3.6 specification for configuration and theming, but does not support all options. The following files form the basis of the labwc -configuration: rc.xml, menu.xml, autostart and environment. +configuration: rc.xml, menu.xml, autostart, shutdown and environment. No configuration files are needed to start and run labwc. @@ -34,11 +34,8 @@ alternative. The configuration directory location can be override with the -C command line option. -All configuration and theme files except autostart are re-loaded on receiving -signal SIGHUP. - -The *autostart* file is executed as a shell script. This is the place for -executing clients for handling background images, panels and similar. +All configuration and theme files except autostart and shutdown are re-loaded on +receiving signal SIGHUP. The *environment* file is parsed as *variable=value* and sets environment variables accordingly. It is recommended to specify keyboard layout settings and @@ -48,6 +45,20 @@ sourced prior to running openbox. Note: Tilde (~) and environment variables in the value are expanded, but subshell syntax and apostrophes are ignored. +The *autostart* file is executed as a shell script after labwc has read its +configuration and set variables defined in the environment file. Additionally, +the environment variables WAYLAND_DISPLAY and (when labwc is built with Xwayland +support) DISPLAY will be defined. This is the place for executing clients for +handling background images, panels and other tasks that should run automatically +when labwc launches. + +The *shutdown* file is executed as a shell script when labwc is preparing to +terminate itself. All environment variables, including WAYLAND_DISPLAY and +DISPLAY, will be available to the script. However, because the script runs +asynchronously with other termination tasks, the shutdown file should not assume +that the display will be usable. This file is useful to perform any custom +operations necessary to finalize a labwc session. + The *menu.xml* file defines the context/root-menus and is described in labwc-menu(5). diff --git a/include/common/string-helpers.h b/include/common/string-helpers.h index 4e204302..6d0ec905 100644 --- a/include/common/string-helpers.h +++ b/include/common/string-helpers.h @@ -43,4 +43,23 @@ void string_truncate_at_pattern(char *buf, const char *pattern); */ char *strdup_printf(const char *fmt, ...); +/** + * str_join - format and join an array of strings with a separator + * @parts: NULL-terminated array of string parts to be joined + * @fmt: printf-style format string applied to each part + * @sep: separator inserted between parts when joining + * + * A new string is allocated to hold the joined result. The user must free the + * returned string. Returns NULL on error. + * + * Each part of the array is converted via the equivalent of sprintf(output, + * fmt, part), so fmt should include a single "%s" format specification. If fmt + * is NULL, a default "%s" will be used to copy each part verbatim. + * + * The separator is arbitrary. When the separator is NULL, a single space will + * be used. + */ +char *str_join(const char * const parts[], + const char *restrict fmt, const char *restrict sep); + #endif /* LABWC_STRING_HELPERS_H */ diff --git a/include/config/session.h b/include/config/session.h index d1efbb60..6de5f05d 100644 --- a/include/config/session.h +++ b/include/config/session.h @@ -15,4 +15,10 @@ void session_environment_init(void); */ void session_autostart_init(void); +/** + * session_shutdown - run session shutdown file as shell script + * Note: Same as `sh ~/.config/labwc/shutdown` (or equivalent XDG config dir) + */ +void session_shutdown(void); + #endif /* LABWC_SESSION_H */ diff --git a/src/common/string-helpers.c b/src/common/string-helpers.c index 37fdf4d0..0a1a8c81 100644 --- a/src/common/string-helpers.c +++ b/src/common/string-helpers.c @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only +#include #include #include #include @@ -83,3 +84,73 @@ strdup_printf(const char *fmt, ...) } return p; } + +char * +str_join(const char * const parts[], + const char *restrict fmt, const char *restrict sep) +{ + assert(parts); + + if (!fmt) { + fmt = "%s"; + } + + if (!sep) { + sep = " "; + } + + size_t size = 0; + size_t n_parts = 0; + + size_t sep_len = strlen(sep); + + /* Count the length of each formatted string */ + for (const char *const *s = parts; *s; ++s) { + int n = snprintf(NULL, 0, fmt, *s); + if (n < 0) { + return NULL; + } + size += (size_t)n; + ++n_parts; + } + + if (n_parts < 1) { + return NULL; + } + + /* Need (n_parts - 1) separators, plus one NULL terminator */ + size += (n_parts - 1) * sep_len + 1; + + /* Concatenate the strings and separators */ + char *buf = xzalloc(size); + char *p = buf; + for (const char *const *s = parts; *s; ++s) { + int n = 0; + + if (p != buf) { + n = snprintf(p, size, "%s", sep); + if (n < 0 || (size_t)n >= size) { + p = NULL; + break; + } + size -= (size_t)n; + p += (size_t)n; + } + + n = snprintf(p, size, fmt, *s); + if (n < 0 || (size_t)n >= size) { + p = NULL; + break; + } + size -= (size_t)n; + p += (size_t)n; + } + + if (!p) { + free(buf); + return NULL; + } + + return buf; +} + diff --git a/src/config/session.c b/src/config/session.c index c87b0865..bc9f6d47 100644 --- a/src/config/session.c +++ b/src/config/session.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only #define _POSIX_C_SOURCE 200809L +#include #include #include #include @@ -9,11 +10,19 @@ #include "common/buf.h" #include "common/dir.h" #include "common/file-helpers.h" +#include "common/mem.h" #include "common/spawn.h" #include "common/string-helpers.h" #include "config/session.h" #include "labwc.h" +static const char *const env_vars[] = { + "DISPLAY", + "WAYLAND_DISPLAY", + "XDG_CURRENT_DESKTOP", + NULL, +}; + static void process_line(char *line) { @@ -65,7 +74,7 @@ read_environment_file(const char *filename) } static void -update_activation_env(const char *env_keys) +update_activation_env(bool initialize) { if (!getenv("DBUS_SESSION_BUS_ADDRESS")) { /* Prevent accidentally auto-launching a dbus session */ @@ -75,13 +84,22 @@ update_activation_env(const char *env_keys) } wlr_log(WLR_INFO, "Updating dbus execution environment"); - char *cmd = strdup_printf("dbus-update-activation-environment %s", env_keys); + char *env_keys = str_join(env_vars, "%s", " "); + char *env_unset_keys = initialize ? NULL : str_join(env_vars, "%s=", " "); + + char *cmd = + strdup_printf("dbus-update-activation-environment %s", + initialize ? env_keys : env_unset_keys); spawn_async_no_shell(cmd); free(cmd); - cmd = strdup_printf("systemctl --user import-environment %s", env_keys); + cmd = strdup_printf("systemctl --user %s %s", + initialize ? "import-environment" : "unset-environment", env_keys); spawn_async_no_shell(cmd); free(cmd); + + free(env_keys); + free(env_unset_keys); } void @@ -120,14 +138,11 @@ session_environment_init(void) paths_destroy(&paths); } -void -session_autostart_init(void) +static void +run_session_script(const char *script) { - /* Update dbus and systemd user environment, each may fail gracefully */ - update_activation_env("DISPLAY WAYLAND_DISPLAY XDG_CURRENT_DESKTOP"); - struct wl_list paths; - paths_config_create(&paths, "autostart"); + paths_config_create(&paths, script); bool should_merge_config = rc.merge_config; struct wl_list *(*iter)(struct wl_list *list); @@ -138,7 +153,7 @@ session_autostart_init(void) if (!file_exists(path->string)) { continue; } - wlr_log(WLR_INFO, "run autostart file %s", path->string); + wlr_log(WLR_INFO, "run session script %s", path->string); char *cmd = strdup_printf("sh %s", path->string); spawn_async_no_shell(cmd); free(cmd); @@ -149,3 +164,20 @@ session_autostart_init(void) } paths_destroy(&paths); } + +void +session_autostart_init(void) +{ + /* Update dbus and systemd user environment, each may fail gracefully */ + update_activation_env(/* initialize */ true); + run_session_script("autostart"); +} + +void +session_shutdown(void) +{ + run_session_script("shutdown"); + + /* Clear the dbus and systemd user environment, each may fail gracefully */ + update_activation_env(/* initialize */ false); +} diff --git a/src/main.c b/src/main.c index 9bfe3a1d..d4a12a80 100644 --- a/src/main.c +++ b/src/main.c @@ -178,6 +178,8 @@ main(int argc, char *argv[]) wl_display_run(server.wl_display); + session_shutdown(); + server_finish(&server); menu_finish(&server); From 22fe8cf546335c10926a14bcc3afc21a3dfd4436 Mon Sep 17 00:00:00 2001 From: David F <145707467+winerysearch@users.noreply.github.com> Date: Sun, 3 Mar 2024 18:47:58 +0100 Subject: [PATCH 27/33] session.c: updated dbus activation environment with more env vars Fixes: #694 --- src/config/session.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/config/session.c b/src/config/session.c index bc9f6d47..73ecb49b 100644 --- a/src/config/session.c +++ b/src/config/session.c @@ -20,7 +20,11 @@ static const char *const env_vars[] = { "DISPLAY", "WAYLAND_DISPLAY", "XDG_CURRENT_DESKTOP", - NULL, + "XCURSOR_SIZE", + "XCURSOR_THEME", + "XDG_SESSION_TYPE", + "LABWC_PID", + NULL }; static void From c9d08f82184a82d5c71ce79f069a4d4707528578 Mon Sep 17 00:00:00 2001 From: "Andrew J. Hesford" Date: Sun, 3 Mar 2024 15:04:24 -0500 Subject: [PATCH 28/33] session: only update activation environment... ...when running DRM backend or by explicit request --- include/config/session.h | 6 +++-- src/common/parse-bool.c | 4 ++++ src/config/session.c | 52 ++++++++++++++++++++++++++++++++++++---- src/main.c | 4 ++-- 4 files changed, 57 insertions(+), 9 deletions(-) diff --git a/include/config/session.h b/include/config/session.h index 6de5f05d..e882f0e8 100644 --- a/include/config/session.h +++ b/include/config/session.h @@ -2,6 +2,8 @@ #ifndef LABWC_SESSION_H #define LABWC_SESSION_H +struct server; + /** * session_environment_init - set enrivonment variables based on = * pairs in `${XDG_CONFIG_DIRS:-/etc/xdg}/lawbc/environment` with user override @@ -13,12 +15,12 @@ void session_environment_init(void); * session_autostart_init - run autostart file as shell script * Note: Same as `sh ~/.config/labwc/autostart` (or equivalent XDG config dir) */ -void session_autostart_init(void); +void session_autostart_init(struct server *server); /** * session_shutdown - run session shutdown file as shell script * Note: Same as `sh ~/.config/labwc/shutdown` (or equivalent XDG config dir) */ -void session_shutdown(void); +void session_shutdown(struct server *server); #endif /* LABWC_SESSION_H */ diff --git a/src/common/parse-bool.c b/src/common/parse-bool.c index 289ac0af..edef698a 100644 --- a/src/common/parse-bool.c +++ b/src/common/parse-bool.c @@ -14,12 +14,16 @@ parse_bool(const char *str, int default_value) return true; } else if (!strcasecmp(str, "on")) { return true; + } else if (!strcmp(str, "1")) { + return true; } else if (!strcasecmp(str, "no")) { return false; } else if (!strcasecmp(str, "false")) { return false; } else if (!strcasecmp(str, "off")) { return false; + } else if (!strcmp(str, "0")) { + return false; } error_not_a_boolean: wlr_log(WLR_ERROR, "(%s) is not a boolean value", str); diff --git a/src/config/session.c b/src/config/session.c index 73ecb49b..56cef717 100644 --- a/src/config/session.c +++ b/src/config/session.c @@ -6,11 +6,14 @@ #include #include #include +#include +#include #include #include "common/buf.h" #include "common/dir.h" #include "common/file-helpers.h" #include "common/mem.h" +#include "common/parse-bool.h" #include "common/spawn.h" #include "common/string-helpers.h" #include "config/session.h" @@ -78,14 +81,53 @@ read_environment_file(const char *filename) } static void -update_activation_env(bool initialize) +backend_check_drm(struct wlr_backend *backend, void *is_drm) { + if (wlr_backend_is_drm(backend)) { + *(bool *)is_drm = true; + } +} + +static bool +should_update_activation(struct server *server) +{ + assert(server); + + static const char *act_env = "LABWC_UPDATE_ACTIVATION_ENV"; + char *env = getenv(act_env); + if (env) { + /* Respect any valid preference from the environment */ + int enabled = parse_bool(env, -1); + + if (enabled == -1) { + wlr_log(WLR_ERROR, "ignoring non-Boolean variable %s", act_env); + } else { + wlr_log(WLR_DEBUG, "%s is %s", + act_env, enabled ? "true" : "false"); + return enabled; + } + } + + /* With no valid preference, update when a DRM backend is in use */ + bool have_drm = false; + wlr_multi_for_each_backend(server->backend, backend_check_drm, &have_drm); + return have_drm; +} + +static void +update_activation_env(struct server *server, bool initialize) +{ + if (!should_update_activation(server)) { + return; + } + if (!getenv("DBUS_SESSION_BUS_ADDRESS")) { /* Prevent accidentally auto-launching a dbus session */ wlr_log(WLR_INFO, "Not updating dbus execution environment: " "DBUS_SESSION_BUS_ADDRESS not set"); return; } + wlr_log(WLR_INFO, "Updating dbus execution environment"); char *env_keys = str_join(env_vars, "%s", " "); @@ -170,18 +212,18 @@ run_session_script(const char *script) } void -session_autostart_init(void) +session_autostart_init(struct server *server) { /* Update dbus and systemd user environment, each may fail gracefully */ - update_activation_env(/* initialize */ true); + update_activation_env(server, /* initialize */ true); run_session_script("autostart"); } void -session_shutdown(void) +session_shutdown(struct server *server) { run_session_script("shutdown"); /* Clear the dbus and systemd user environment, each may fail gracefully */ - update_activation_env(/* initialize */ false); + update_activation_env(server, /* initialize */ false); } diff --git a/src/main.c b/src/main.c index d4a12a80..35b2f3fa 100644 --- a/src/main.c +++ b/src/main.c @@ -171,14 +171,14 @@ main(int argc, char *argv[]) menu_init(&server); - session_autostart_init(); + session_autostart_init(&server); if (startup_cmd) { spawn_async_no_shell(startup_cmd); } wl_display_run(server.wl_display); - session_shutdown(); + session_shutdown(&server); server_finish(&server); From 0af7bc886af91beb5d4361cd33b84cf532ae314d Mon Sep 17 00:00:00 2001 From: "Andrew J. Hesford" Date: Sun, 3 Mar 2024 19:33:10 -0500 Subject: [PATCH 29/33] docs/labwc.1: restructure, document session management --- docs/labwc.1.scd | 54 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/docs/labwc.1.scd b/docs/labwc.1.scd index ca9f1ae9..64eb1a98 100644 --- a/docs/labwc.1.scd +++ b/docs/labwc.1.scd @@ -2,7 +2,7 @@ labwc(1) # NAME -labwc - a wayland stacking compositor +labwc - a Wayland stacking compositor # SYNOPSIS @@ -16,8 +16,10 @@ It is light-weight and independent with a focus on simply stacking windows well and rendering some window decorations. Where practicable it uses clients for wall-paper, panels, screenshots and so on. +# SIGNALS + The compositor will exit or reload its configuration upon receiving SIGTERM -and SIGHUP respectively. For example: +and SIGHUP respectively. For example: ``` kill -s $LABWC_PID @@ -40,7 +42,7 @@ the `--exit` and `--reconfigure` options use. Enable full logging, including debug information *-e, --exit* - Exit the compositor + Exit the compositor by sending SIGTERM to `$LABWC_PID` *-h, --help* Show help message and quit @@ -49,7 +51,7 @@ the `--exit` and `--reconfigure` options use. Merge user config/theme files in all XDG Base Directories *-r, --reconfigure* - Reload the compositor configuration + Reload the compositor configuration by sending SIGHUP to `$LABWC_PID` *-s, --startup* Run command on startup @@ -60,6 +62,48 @@ the `--exit` and `--reconfigure` options use. *-V, --verbose* Enable more verbose logging +# SESSION MANAGEMENT + +To enable the use of graphical clients launched via D-Bus or systemd servie +activation, labwc can update both activation environments on launch. Provided +that labwc is aware of an active D-Bus user session (*i.e.*, the environment +variable `DBUS_SESSION_BUS_ADDRESS` is defined), the compositor will invoke the +commands + +``` +dbus-update-activation-environment +systemctl --user import-environment +``` + +(when available) to notify D-Bus and systemd with the values of the following +environment variables: + +``` +WAYLAND_DISPLAY +DISPLAY +XDG_CURRENT_DESKTOP +XDG_SESSION_TYPE +XCURSOR_SIZE +XCURSOR_THEME +LABWC_PWD +``` + +This behavior is enabled by default whenever labwc uses the "DRM" wlroots +backend (which implies that labwc is the primary compositor on the console). +When other backends are employed (for example, when labwc runs nested in another +Wayland compositor or an X11 server), updates to the activation environment are +disabled by default. Updates to the activation environment can be forced by +setting the environment variable `LABWC_UPDATE_ACTIVATION_ENV` to one of the +truthy values `1`, `true`, `yes` or `on`; or suppressed by setting the variable +to one of the falsy values `0`, `false`, `no` or `off`. + +Whenever labwc updates the activation environment on launch, it will also +attempt to clear the activation environment on exit. For D-Bus, which does not +provide a means for properly un-setting variables in the activation environment, +this is accomplished by setting the session variables to empty strings. For +systemd, the command `systemctl --user unset-environment` will be invoked to +actually remove the variables from the activation environment. + # SEE ALSO -labwc-config(5), labwc-theme(5), labwc-actions(5) +labwc-actions(5), labwc-config(5), labwc-menu(5), labwc-theme(5) From c78750283f7af344628908defb86e7e0bd0924f9 Mon Sep 17 00:00:00 2001 From: John Lindgren Date: Fri, 10 Nov 2023 23:44:41 -0500 Subject: [PATCH 30/33] key-state: use struct assignment --- src/input/key-state.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/input/key-state.c b/src/input/key-state.c index c512a762..8ce66ff0 100644 --- a/src/input/key-state.c +++ b/src/input/key-state.c @@ -79,9 +79,7 @@ key_state_pressed_sent_keycodes(void) report(&bound, "before - bound:"); /* pressed_sent = pressed - bound */ - memcpy(pressed_sent.keys, pressed.keys, - MAX_PRESSED_KEYS * sizeof(uint32_t)); - pressed_sent.nr_keys = pressed.nr_keys; + pressed_sent = pressed; for (int i = 0; i < bound.nr_keys; ++i) { remove_key(&pressed_sent, bound.keys[i]); } From f250c6ba129cd647603ed8feb20b65fd7ae2f70a Mon Sep 17 00:00:00 2001 From: Standreas Date: Mon, 4 Mar 2024 22:20:08 +0100 Subject: [PATCH 31/33] Add weblate information (#1581) ...and some sub-headings --- CONTRIBUTING.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ef6ca30a..4954400f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -350,6 +350,17 @@ Base both bugfixes and new features on `master`. # Native Language Support +## Translators + +### Weblate Instance + +Translators can create an account at [LXQt Weblate](https://translate.lxqt-project.org/projects/labwc/labwc/) +and use the web interface. Adding new languages should work, otherwise the +administrators can be contacted. Suggestions for improving existing translations +can be added without account. + +### Github Pull Request + Translators can add their `MY_LOCALE.po` files to the `po` directory based on `po/labwc.pot` and issue a pull request. To do this they can generate their `MY_LOCALE.po` file in a few steps: @@ -363,6 +374,8 @@ translation strings under each English string. [See this tutorial for further guidance](https://www.labri.fr/perso/fleury/posts/programming/a-quick-gettext-tutorial.html) +## Coders + Code contributors may need to update relevant files if their additions affect UI elements (at the moment only `src/menu/menu.c`). In this case the `po/labwc.pot` file needs to be updated so that translators can From 74501bc7fadc3b152dc9e1f18d87f154bdc1cb03 Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Tue, 27 Feb 2024 23:25:45 +0100 Subject: [PATCH 32/33] src/output.c: restore flicker free resize when running nested PR #1301 did partly revert the first variant because `lab_wlr_scene_output_commit()` (which uses the `output->pending` state in contrast to `wlr_scene_output_commit()`) was deemd to cause 'frozen' frames during video playback (#1273). We are now back at using `lab_wlr_scene_output_commit()` for unrelated reasons and the cause of the original issue #1273 was likely that `wlr_scene_output_send_frame_done()` was only sent on a successful commit. This was changed to always be sent. So lets restore the flicker free nested resize as well. --- src/output.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/output.c b/src/output.c index e1c615e7..16eee4b8 100644 --- a/src/output.c +++ b/src/output.c @@ -150,6 +150,32 @@ output_request_state_notify(struct wl_listener *listener, void *data) struct output *output = wl_container_of(listener, output, request_state); const struct wlr_output_event_request_state *event = data; + /* + * If wlroots ever requests other state changes here we could + * restore more of ddc9047a67cd53b2948f71fde1bbe9118000dd3f. + */ + if (event->state->committed == WLR_OUTPUT_STATE_MODE) { + /* Only the mode has changed */ + switch (event->state->mode_type) { + case WLR_OUTPUT_STATE_MODE_FIXED: + wlr_output_set_mode(output->wlr_output, event->state->mode); + break; + case WLR_OUTPUT_STATE_MODE_CUSTOM: + wlr_output_set_custom_mode(output->wlr_output, + event->state->custom_mode.width, + event->state->custom_mode.height, + event->state->custom_mode.refresh); + break; + } + wlr_output_schedule_frame(output->wlr_output); + return; + } + + /* + * Fallback path for everything that we didn't handle above. + * The commit will cause a black frame injection so this + * path causes flickering during resize of nested outputs. + */ if (!wlr_output_commit_state(output->wlr_output, event->state)) { wlr_log(WLR_ERROR, "Backend requested a new state that could not be applied"); } From 7e60c57b8181960c006f03d4c2ce48250ed71b78 Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Mon, 26 Feb 2024 00:54:57 +0100 Subject: [PATCH 33/33] src/server.c: filter out xwayland shell for usual clients --- protocols/meson.build | 1 + src/server.c | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/protocols/meson.build b/protocols/meson.build index 0ec9154b..acaf0215 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -18,6 +18,7 @@ server_protocols = [ wl_protocol_dir / 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml', wl_protocol_dir / 'staging/cursor-shape/cursor-shape-v1.xml', wl_protocol_dir / 'staging/drm-lease/drm-lease-v1.xml', + wl_protocol_dir / 'staging/xwayland-shell/xwayland-shell-v1.xml', wl_protocol_dir / 'staging/tearing-control/tearing-control-v1.xml', 'wlr-layer-shell-unstable-v1.xml', 'wlr-input-inhibitor-unstable-v1.xml', diff --git a/src/server.c b/src/server.c index c0ee7682..e1e48dd6 100644 --- a/src/server.c +++ b/src/server.c @@ -17,6 +17,7 @@ #include #if HAVE_XWAYLAND #include +#include "xwayland-shell-v1-protocol.h" #endif #include "drm-lease-v1-protocol.h" #include "config/rcxml.h" @@ -172,9 +173,11 @@ server_global_filter(const struct wl_client *client, const struct wl_global *glo (void)iface; (void)server; #if HAVE_XWAYLAND - struct wl_client *xwayland_client = - server->xwayland ? server->xwayland->server->client : NULL; - if (xwayland_client && client == xwayland_client) { + struct wl_client *xwayland_client = (server->xwayland && server->xwayland->server) + ? server->xwayland->server->client + : NULL; + + if (client == xwayland_client) { /* * Filter out wp_drm_lease_device_v1 for now as it is resulting in * issues with Xwayland applications lagging over time. @@ -184,6 +187,9 @@ server_global_filter(const struct wl_client *client, const struct wl_global *glo if (!strcmp(iface->name, wp_drm_lease_device_v1_interface.name)) { return false; } + } else if (!strcmp(iface->name, xwayland_shell_v1_interface.name)) { + /* Filter out the xwayland shell for usual clients */ + return false; } #endif