From ef3dbbf29ac818e21503d647fcbf947bcd85921e Mon Sep 17 00:00:00 2001 From: Consus Date: Tue, 28 Jun 2022 22:47:48 +0300 Subject: [PATCH 01/16] Fix usable area calculation Currently if a surface with exclusive zone is created prior to regular surfaces, the size of the exclusize zone does not affect the usable area for regular surfaces. This for example results in notifications being rendered over the statusbar. This commit fixes the issue by handling the surfaces with exclusive zones first. Fixes #420. --- src/layers.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/layers.c b/src/layers.c index d36e11a5..8a03d3cb 100644 --- a/src/layers.c +++ b/src/layers.c @@ -37,11 +37,29 @@ layers_arrange(struct output *output) int nr_layers = sizeof(output->layers) / sizeof(output->layers[0]); for (int i = 0; i < nr_layers; i++) { struct lab_layer_surface *lab_layer_surface; + + /* + * First we go over the list of surfaces that have + * exclusive_zone set (e.g. statusbars) because we have to + * determine the usable area before processing regular layouts. + */ wl_list_for_each(lab_layer_surface, &output->layers[i], link) { struct wlr_scene_layer_surface_v1 *scene_layer_surface = lab_layer_surface->scene_layer_surface; - wlr_scene_layer_surface_v1_configure( - scene_layer_surface, &full_area, &usable_area); + if (scene_layer_surface->layer_surface->current.exclusive_zone) { + wlr_scene_layer_surface_v1_configure( + scene_layer_surface, &full_area, &usable_area); + } + } + + /* Now we process regular layouts */ + wl_list_for_each(lab_layer_surface, &output->layers[i], link) { + struct wlr_scene_layer_surface_v1 *scene_layer_surface = + lab_layer_surface->scene_layer_surface; + if (!scene_layer_surface->layer_surface->current.exclusive_zone) { + wlr_scene_layer_surface_v1_configure( + scene_layer_surface, &full_area, &usable_area); + } } wlr_scene_node_set_position(&output->layer_tree[i]->node, @@ -350,7 +368,7 @@ new_layer_surface_notify(struct wl_listener *listener, void *data) return; } - wl_list_insert(&output->layers[layer_surface->pending.layer], + wl_list_insert(output->layers[layer_surface->pending.layer].prev, &surface->link); /* * Temporarily set the layer's current state to pending so that From 09915b8f43f91a17b9b434b7bfb765055833640d Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Tue, 28 Jun 2022 19:42:40 +0200 Subject: [PATCH 02/16] src/ssd/ssd.c: Keep view->margin in sync when toggling decorations Fixes #409 --- include/ssd.h | 1 - src/server.c | 1 - src/ssd/ssd.c | 16 +++++++--------- src/xdg.c | 2 -- src/xwayland.c | 7 +------ 5 files changed, 8 insertions(+), 19 deletions(-) diff --git a/include/ssd.h b/include/ssd.h index 302d78d8..524f3b68 100644 --- a/include/ssd.h +++ b/include/ssd.h @@ -134,7 +134,6 @@ struct ssd_hover_state { /* Public SSD API */ void ssd_create(struct view *view); -void ssd_hide(struct view *view); void ssd_set_active(struct view *view); void ssd_update_title(struct view *view); void ssd_update_geometry(struct view *view); diff --git a/src/server.c b/src/server.c index df9d8935..857d3e49 100644 --- a/src/server.c +++ b/src/server.c @@ -42,7 +42,6 @@ reload_config_and_theme(void) if (!view->mapped || !view->ssd.enabled) { continue; } - view->margin = ssd_thickness(view); ssd_reload(view); } diff --git a/src/ssd/ssd.c b/src/ssd/ssd.c index 94dcf501..04c78575 100644 --- a/src/ssd/ssd.c +++ b/src/ssd/ssd.c @@ -17,6 +17,10 @@ struct border ssd_thickness(struct view *view) { + if (!view->ssd.enabled) { + struct border border = { 0 }; + return border; + } struct theme *theme = view->server->theme; struct border border = { .top = theme->title_height + theme->border_width, @@ -159,6 +163,7 @@ ssd_create(struct view *view) ssd_extents_create(view); ssd_border_create(view); ssd_titlebar_create(view); + view->margin = ssd_thickness(view); } void @@ -171,10 +176,12 @@ ssd_update_geometry(struct view *view) if (!view->ssd.enabled) { if (view->ssd.tree->node.enabled) { wlr_scene_node_set_enabled(&view->ssd.tree->node, false); + view->margin = ssd_thickness(view); } return; } else if (!view->ssd.tree->node.enabled) { wlr_scene_node_set_enabled(&view->ssd.tree->node, true); + view->margin = ssd_thickness(view); } int width = view->w; @@ -198,15 +205,6 @@ ssd_update_geometry(struct view *view) view->ssd.state.y = view->y; } -void -ssd_hide(struct view *view) -{ - if (!view->ssd.tree) { - return; - } - wlr_scene_node_set_enabled(&view->ssd.tree->node, false); -} - void ssd_reload(struct view *view) { if (!view->ssd.tree) { diff --git a/src/xdg.c b/src/xdg.c index 611691c6..b7c9edf3 100644 --- a/src/xdg.c +++ b/src/xdg.c @@ -298,7 +298,6 @@ xdg_toplevel_view_map(struct view *view) view->ssd.enabled = has_ssd(view); if (view->ssd.enabled) { - view->margin = ssd_thickness(view); ssd_create(view); } @@ -311,7 +310,6 @@ xdg_toplevel_view_map(struct view *view) } view_discover_output(view); - view->been_mapped = true; } diff --git a/src/xwayland.c b/src/xwayland.c index 334dd3b2..1efd4415 100644 --- a/src/xwayland.c +++ b/src/xwayland.c @@ -329,7 +329,7 @@ map(struct view *view) if (!view->been_mapped) { view->ssd.enabled = want_deco(view); if (view->ssd.enabled) { - view->margin = ssd_thickness(view); + ssd_create(view); } if (!view->maximized && !view->fullscreen) { @@ -341,11 +341,6 @@ map(struct view *view) } view_discover_output(view); - - if (view->ssd.enabled) { - /* Create ssd after view_disover_output() had been called */ - ssd_create(view); - } view->been_mapped = true; } From f4aa6118e9af1ce0e2a6b84ed61d7c1fd9531c89 Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Thu, 30 Jun 2022 20:02:24 +0200 Subject: [PATCH 03/16] src/layers.c: Adjust views based on usable_area changes --- include/labwc.h | 1 + src/desktop.c | 10 ++++++++++ src/layers.c | 4 +++- src/output.c | 5 +---- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/include/labwc.h b/include/labwc.h index 416fb03c..be6a629d 100644 --- a/include/labwc.h +++ b/include/labwc.h @@ -460,6 +460,7 @@ void foreign_toplevel_handle_create(struct view *view); void desktop_move_to_front(struct view *view); void desktop_move_to_back(struct view *view); void desktop_focus_and_activate_view(struct seat *seat, struct view *view); +void desktop_arrange_all_views(struct server *server); enum lab_cycle_dir { LAB_CYCLE_DIR_NONE, diff --git a/src/desktop.c b/src/desktop.c index b19cd4be..5a3ad8bc 100644 --- a/src/desktop.c +++ b/src/desktop.c @@ -99,6 +99,16 @@ deactivate_all_views(struct server *server) } } +void +desktop_arrange_all_views(struct server *server) +{ + /* Adjust window positions/sizes */ + struct view *view; + wl_list_for_each(view, &server->views, link) { + view_adjust_for_layout_change(view); + } +} + void desktop_focus_and_activate_view(struct seat *seat, struct view *view) { diff --git a/src/layers.c b/src/layers.c index 8a03d3cb..47c0d021 100644 --- a/src/layers.c +++ b/src/layers.c @@ -98,7 +98,9 @@ layers_arrange(struct output *output) !seat->focused_layer->current.keyboard_interactive) { seat_set_focus_layer(seat, NULL); } - /* FIXME: should we call a desktop_arrange_all_views() here? */ + + /* Finally re-arrange all views based on usable_area */ + desktop_arrange_all_views(server); } static void diff --git a/src/output.c b/src/output.c index d2634cf7..688640f3 100644 --- a/src/output.c +++ b/src/output.c @@ -209,10 +209,7 @@ static void output_update_for_layout_change(struct server *server) { /* Adjust window positions/sizes */ - struct view *view; - wl_list_for_each(view, &server->views, link) { - view_adjust_for_layout_change(view); - } + desktop_arrange_all_views(server); /* * "Move" each wlr_output_cursor (in per-output coordinates) to From 992089e9014830ab5e5aebc94afa926fed127889 Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Fri, 1 Jul 2022 00:55:15 +0200 Subject: [PATCH 04/16] src/layers.c: Prevent re-arranging views if usable_area didn't change --- src/layers.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/layers.c b/src/layers.c index 47c0d021..674deaa9 100644 --- a/src/layers.c +++ b/src/layers.c @@ -25,6 +25,7 @@ layers_arrange(struct output *output) wlr_output_effective_resolution(output->wlr_output, &full_area.width, &full_area.height); struct wlr_box usable_area = full_area; + struct wlr_box old_usable_area = output->usable_area; struct server *server = output->server; struct wlr_scene_output *scene_output = @@ -100,7 +101,10 @@ layers_arrange(struct output *output) } /* Finally re-arrange all views based on usable_area */ - desktop_arrange_all_views(server); + if (old_usable_area.width != output->usable_area.width + || old_usable_area.height != output->usable_area.height) { + desktop_arrange_all_views(server); + } } static void From 3a4b55886d2691680bd6859ef30d91435b1f46b3 Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Fri, 1 Jul 2022 02:07:40 +0200 Subject: [PATCH 05/16] src/view.c: Convert SnapToEdge to use view_apply_xxx_geometry framework --- include/labwc.h | 1 + src/interactive.c | 1 + src/view.c | 230 +++++++++++++++++++++++++--------------------- 3 files changed, 128 insertions(+), 104 deletions(-) diff --git a/include/labwc.h b/include/labwc.h index be6a629d..7fc0e0a5 100644 --- a/include/labwc.h +++ b/include/labwc.h @@ -306,6 +306,7 @@ struct view { bool been_mapped; bool minimized; bool maximized; + uint32_t tiled; /* private, enum view_edge in src/view.c */ struct wlr_output *fullscreen; /* geometry of the wlr_surface contained within the view */ diff --git a/src/interactive.c b/src/interactive.c index 8ade121a..c7dab3dc 100644 --- a/src/interactive.c +++ b/src/interactive.c @@ -40,6 +40,7 @@ interactive_begin(struct view *view, enum input_mode mode, uint32_t edges) return; } } + view->tiled = 0; /* * This function sets up an interactive move or resize operation, where diff --git a/src/view.c b/src/view.c index e82dd6d3..8c3938fb 100644 --- a/src/view.c +++ b/src/view.c @@ -10,6 +10,89 @@ #define MAX(a, b) (((a) > (b)) ? (a) : (b)) +/** + * All view_apply_xxx_geometry() functions must *not* modify + * any state besides repositioning or resizing the view. + * + * They may be called repeatably during output layout changes. + */ + +enum view_edge { + VIEW_EDGE_INVALID = 0, + + VIEW_EDGE_LEFT, + VIEW_EDGE_RIGHT, + VIEW_EDGE_UP, + VIEW_EDGE_DOWN, + VIEW_EDGE_CENTER, +}; + +static enum view_edge +view_edge_invert(enum view_edge edge) +{ + switch (edge) { + case VIEW_EDGE_LEFT: + return VIEW_EDGE_RIGHT; + case VIEW_EDGE_RIGHT: + return VIEW_EDGE_LEFT; + case VIEW_EDGE_UP: + return VIEW_EDGE_DOWN; + case VIEW_EDGE_DOWN: + return VIEW_EDGE_UP; + case VIEW_EDGE_CENTER: + case VIEW_EDGE_INVALID: + default: + return VIEW_EDGE_INVALID; + } +} + +static struct wlr_box +view_get_edge_snap_box(struct view *view, struct output *output, + enum view_edge edge) +{ + struct wlr_box usable = output_usable_area_in_layout_coords(output); + if (usable.height == output->wlr_output->height + && output->wlr_output->scale != 1) { + usable.height /= output->wlr_output->scale; + } + if (usable.width == output->wlr_output->width + && output->wlr_output->scale != 1) { + usable.width /= output->wlr_output->scale; + } + + int x_offset = edge == VIEW_EDGE_RIGHT + ? (usable.width + rc.gap) / 2 : rc.gap; + int y_offset = edge == VIEW_EDGE_DOWN + ? (usable.height + rc.gap) / 2 : rc.gap; + + int base_width, base_height; + switch (edge) { + case VIEW_EDGE_LEFT: + case VIEW_EDGE_RIGHT: + base_width = (usable.width - 3 * rc.gap) / 2; + base_height = usable.height - 2 * rc.gap; + break; + case VIEW_EDGE_UP: + case VIEW_EDGE_DOWN: + base_width = usable.width - 2 * rc.gap; + base_height = (usable.height - 3 * rc.gap) / 2; + break; + default: + case VIEW_EDGE_CENTER: + base_width = usable.width - 2 * rc.gap; + base_height = usable.height - 2 * rc.gap; + break; + } + struct wlr_box dst = { + .x = x_offset + usable.x + view->margin.left, + .y = y_offset + usable.y + view->margin.top, + .width = base_width - view->margin.left - view->margin.right, + .height = base_height - view->margin.top - view->margin.bottom, + }; + + return dst; +} + void view_set_activated(struct view *view, bool activated) { @@ -185,6 +268,27 @@ view_center(struct view *view) } } +static void +view_apply_tiled_geometry(struct view *view, struct output *output) +{ + assert(view->tiled); + if (!output) { + output = view_output(view); + } + if (!output) { + wlr_log(WLR_ERROR, "Can't tile: no output"); + return; + } + + struct wlr_box dst = view_get_edge_snap_box(view, output, view->tiled); + if (view->w == dst.width && view->h == dst.height) { + /* move horizontally/vertically without changing size */ + view_move(view, dst.x, dst.y); + } else { + view_move_resize(view, dst); + } +} + static void view_apply_fullscreen_geometry(struct view *view, struct wlr_output *wlr_output) { @@ -515,35 +619,6 @@ view_move_to_edge(struct view *view, const char *direction) view_move(view, x, y); } -enum view_edge { - VIEW_EDGE_INVALID, - - VIEW_EDGE_LEFT, - VIEW_EDGE_RIGHT, - VIEW_EDGE_UP, - VIEW_EDGE_DOWN, - VIEW_EDGE_CENTER, -}; - -static enum view_edge -view_edge_invert(enum view_edge edge) -{ - switch (edge) { - case VIEW_EDGE_LEFT: - return VIEW_EDGE_RIGHT; - case VIEW_EDGE_RIGHT: - return VIEW_EDGE_LEFT; - case VIEW_EDGE_UP: - return VIEW_EDGE_DOWN; - case VIEW_EDGE_DOWN: - return VIEW_EDGE_UP; - case VIEW_EDGE_CENTER: - case VIEW_EDGE_INVALID: - default: - return VIEW_EDGE_INVALID; - } -} - static enum view_edge view_edge_parse(const char *direction) { @@ -565,53 +640,6 @@ view_edge_parse(const char *direction) } } -static struct wlr_box -view_get_edge_snap_box(struct view *view, struct output *output, - enum view_edge edge) -{ - struct wlr_box usable = output_usable_area_in_layout_coords(output); - if (usable.height == output->wlr_output->height - && output->wlr_output->scale != 1) { - usable.height /= output->wlr_output->scale; - } - if (usable.width == output->wlr_output->width - && output->wlr_output->scale != 1) { - usable.width /= output->wlr_output->scale; - } - - int x_offset = edge == VIEW_EDGE_RIGHT - ? (usable.width + rc.gap) / 2 : rc.gap; - int y_offset = edge == VIEW_EDGE_DOWN - ? (usable.height + rc.gap) / 2 : rc.gap; - - int base_width, base_height; - switch (edge) { - case VIEW_EDGE_LEFT: - case VIEW_EDGE_RIGHT: - base_width = (usable.width - 3 * rc.gap) / 2; - base_height = usable.height - 2 * rc.gap; - break; - case VIEW_EDGE_UP: - case VIEW_EDGE_DOWN: - base_width = usable.width - 2 * rc.gap; - base_height = (usable.height - 3 * rc.gap) / 2; - break; - default: - case VIEW_EDGE_CENTER: - base_width = usable.width - 2 * rc.gap; - base_height = usable.height - 2 * rc.gap; - break; - } - struct wlr_box dst = { - .x = x_offset + usable.x + view->margin.left, - .y = y_offset + usable.y + view->margin.top, - .width = base_width - view->margin.left - view->margin.right, - .height = base_height - view->margin.top - view->margin.bottom, - }; - - return dst; -} - void view_snap_to_edge(struct view *view, const char *direction) { @@ -630,50 +658,44 @@ view_snap_to_edge(struct view *view, const char *direction) return; } - struct wlr_box dst = view_get_edge_snap_box(view, output, edge); - - if (view->x == dst.x && view->y == dst.y && view->w == dst.width - && view->h == dst.height) { - /* Move over to the next screen if this is already snapped. */ - struct wlr_box usable = - output_usable_area_in_layout_coords(output); + if (view->tiled == edge) { + /* We are already tiled for this edge and thus should switch outputs */ + 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: - dst.x -= (usable.width / 2) + 1; + new_output = wlr_output_layout_adjacent_output( + layout, WLR_DIRECTION_LEFT, current_output, 1, 0); break; case VIEW_EDGE_RIGHT: - dst.x += (usable.width / 2) + 1; + new_output = wlr_output_layout_adjacent_output( + layout, WLR_DIRECTION_RIGHT, current_output, 1, 0); break; case VIEW_EDGE_UP: - dst.y -= (usable.height / 2) + 1; + new_output = wlr_output_layout_adjacent_output( + layout, WLR_DIRECTION_UP, current_output, 0, 1); break; case VIEW_EDGE_DOWN: - dst.y += (usable.height / 2) + 1; + new_output = wlr_output_layout_adjacent_output( + layout, WLR_DIRECTION_DOWN, current_output, 0, 1); break; default: break; } - - struct wlr_output *new_wlr_output = wlr_output_layout_output_at( - view->server->output_layout, dst.x, dst.y); - struct output *new_output = - output_from_wlr_output(view->server, new_wlr_output); - - if (new_output == output || !new_output - || edge == VIEW_EDGE_CENTER) { + if (new_output && new_output != current_output) { + /* Move to next output */ + edge = view_edge_invert(edge); + output = output_from_wlr_output(view->server, new_output); + } else { + /* No more output to move to */ return; } - - dst = view_get_edge_snap_box(view, new_output, - view_edge_invert(edge)); } - if (view->w == dst.width && view->h == dst.height) { - /* move horizontally/vertically without changing size */ - view_move(view, dst.x, dst.y); - } else { - view_move_resize(view, dst); - } + /* TODO: store old geometry if !maximized && !fullscreen && !tiled */ + view->tiled = edge; + view_apply_tiled_geometry(view, output); } const char * From 8ed62b4860db1ecd9829240a262a793cc12e10e3 Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Fri, 1 Jul 2022 02:12:23 +0200 Subject: [PATCH 06/16] src/view.c: Re-arrange tiled windows on layout change --- src/view.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/view.c b/src/view.c index 8c3938fb..a7aadc28 100644 --- a/src/view.c +++ b/src/view.c @@ -525,6 +525,9 @@ view_adjust_for_layout_change(struct view *view) } else if (view->maximized) { /* recompute maximized geometry */ view_apply_maximized_geometry(view); + } else if (view->tiled) { + /* recompute tiled geometry */ + view_apply_tiled_geometry(view, NULL); } else { /* reposition view if it's offscreen */ struct wlr_box box = { view->x, view->y, view->w, view->h }; From 2d02fec4b2c4c52de4917048487956095778ef65 Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Fri, 1 Jul 2022 19:40:27 +0200 Subject: [PATCH 07/16] src/view.c: Re-arrange tiled windows on decoration change --- src/view.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/view.c b/src/view.c index a7aadc28..a6b46427 100644 --- a/src/view.c +++ b/src/view.c @@ -426,6 +426,8 @@ view_toggle_decorations(struct view *view) ssd_update_geometry(view); if (view->maximized) { view_apply_maximized_geometry(view); + } else if (view->tiled) { + view_apply_tiled_geometry(view, NULL); } } } @@ -457,6 +459,8 @@ view_set_decorations(struct view *view, bool decorations) ssd_update_geometry(view); if (view->maximized) { view_apply_maximized_geometry(view); + } else if (view->tiled) { + view_apply_tiled_geometry(view, NULL); } } } From 2f7b1fd5fbb19f58fa5e8a0db9de83d0e6ed385b Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Fri, 1 Jul 2022 20:40:18 +0200 Subject: [PATCH 08/16] src/view.c: Re-arrange tiled windows on un-fullscreen and un-maximize --- src/view.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/view.c b/src/view.c index a6b46427..192e02c4 100644 --- a/src/view.c +++ b/src/view.c @@ -407,7 +407,11 @@ view_maximize(struct view *view, bool maximize) view->maximized = true; } else { /* unmaximize */ - view_apply_unmaximized_geometry(view); + if (view->tiled) { + view_apply_tiled_geometry(view, NULL); + } else { + view_apply_unmaximized_geometry(view); + } view->maximized = false; } } @@ -501,6 +505,8 @@ view_set_fullscreen(struct view *view, bool fullscreen, /* restore to normal */ if (view->maximized) { view_apply_maximized_geometry(view); + } else if (view->tiled) { + view_apply_tiled_geometry(view, NULL); } else { view_apply_unmaximized_geometry(view); } From 7bdcef51b794e6791f9a89df41a22e9f555ffe58 Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Fri, 1 Jul 2022 20:42:09 +0200 Subject: [PATCH 09/16] src/view.c: Prevent SnapToEdge while in fullscreen --- src/view.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/view.c b/src/view.c index 192e02c4..44349cfd 100644 --- a/src/view.c +++ b/src/view.c @@ -660,6 +660,9 @@ view_snap_to_edge(struct view *view, const char *direction) wlr_log(WLR_ERROR, "no view"); return; } + if (view->fullscreen) { + return; + } struct output *output = view_output(view); if (!output) { wlr_log(WLR_ERROR, "no output"); From 02595eefaaf16beee2d8b933d0f70c56481a6e6f Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Fri, 1 Jul 2022 20:44:40 +0200 Subject: [PATCH 10/16] src/view.c: Unmaximize on SnapToEdge --- src/view.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/view.c b/src/view.c index 44349cfd..53d61628 100644 --- a/src/view.c +++ b/src/view.c @@ -709,6 +709,10 @@ view_snap_to_edge(struct view *view, const char *direction) } } + if (view->maximized) { + view_maximize(view, false); + } + /* TODO: store old geometry if !maximized && !fullscreen && !tiled */ view->tiled = edge; view_apply_tiled_geometry(view, output); From 5585977f723f88eb6d6c560e60b3152073a8028e Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Fri, 1 Jul 2022 19:34:56 +0200 Subject: [PATCH 11/16] Rename unmaximized_geometry to natural_geometry --- include/labwc.h | 4 ++-- src/interactive.c | 16 ++++++++-------- src/view.c | 36 ++++++++++++++++++------------------ 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/include/labwc.h b/include/labwc.h index 7fc0e0a5..7dd863bd 100644 --- a/include/labwc.h +++ b/include/labwc.h @@ -312,8 +312,8 @@ struct view { /* geometry of the wlr_surface contained within the view */ int x, y, w, h; - /* geometry before maximize */ - struct wlr_box unmaximized_geometry; + /* user defined geometry before maximize / tiling / fullscreen */ + struct wlr_box natural_geometry; /* * margin refers to the space between the extremities of the diff --git a/src/interactive.c b/src/interactive.c index c7dab3dc..c4dde0cc 100644 --- a/src/interactive.c +++ b/src/interactive.c @@ -20,11 +20,11 @@ interactive_begin(struct view *view, enum input_mode mode, uint32_t edges) if (view->maximized) { if (mode == LAB_INPUT_STATE_MOVE) { int new_x = max_move_scale(view->server->seat.cursor->x, - view->x, view->w, view->unmaximized_geometry.width); + view->x, view->w, view->natural_geometry.width); int new_y = max_move_scale(view->server->seat.cursor->y, - view->y, view->h, view->unmaximized_geometry.height); - view->unmaximized_geometry.x = new_x; - view->unmaximized_geometry.y = new_y; + view->y, view->h, view->natural_geometry.height); + view->natural_geometry.x = new_x; + view->natural_geometry.y = new_y; view_maximize(view, false); /* * view_maximize() indirectly calls view->impl->configure @@ -34,8 +34,8 @@ interactive_begin(struct view *view, enum input_mode mode, uint32_t edges) */ view->x = new_x; view->y = new_y; - view->w = view->unmaximized_geometry.width; - view->h = view->unmaximized_geometry.height; + view->w = view->natural_geometry.width; + view->h = view->natural_geometry.height; } else { return; } @@ -102,9 +102,9 @@ interactive_end(struct view *view) * When unmaximizing later on restore * original position */ - view->unmaximized_geometry.x = + view->natural_geometry.x = view->server->grab_box.x; - view->unmaximized_geometry.y = + view->natural_geometry.y = view->server->grab_box.y; } else { view_snap_to_edge(view, "up"); diff --git a/src/view.c b/src/view.c index 53d61628..af291228 100644 --- a/src/view.c +++ b/src/view.c @@ -344,13 +344,13 @@ view_apply_maximized_geometry(struct view *view) static void set_fallback_geometry(struct view *view) { - view->unmaximized_geometry.width = LAB_FALLBACK_WIDTH; - view->unmaximized_geometry.height = LAB_FALLBACK_HEIGHT; + view->natural_geometry.width = LAB_FALLBACK_WIDTH; + view->natural_geometry.height = LAB_FALLBACK_HEIGHT; view_compute_centered_position(view, - view->unmaximized_geometry.width, - view->unmaximized_geometry.height, - &view->unmaximized_geometry.x, - &view->unmaximized_geometry.y); + view->natural_geometry.width, + view->natural_geometry.height, + &view->natural_geometry.x, + &view->natural_geometry.y); } static void @@ -361,18 +361,18 @@ view_apply_unmaximized_geometry(struct view *view) * width/height may still be zero in which case we set some fallback * values. This is the case with foot and Qt applications. */ - if (wlr_box_empty(&view->unmaximized_geometry)) { + if (wlr_box_empty(&view->natural_geometry)) { set_fallback_geometry(view); } struct wlr_output_layout *layout = view->server->output_layout; if (wlr_output_layout_intersects(layout, NULL, - &view->unmaximized_geometry)) { + &view->natural_geometry)) { /* restore to original geometry */ - view_move_resize(view, view->unmaximized_geometry); + view_move_resize(view, view->natural_geometry); } else { /* reposition if original geometry is offscreen */ - struct wlr_box box = view->unmaximized_geometry; + struct wlr_box box = view->natural_geometry; if (view_compute_centered_position(view, box.width, box.height, &box.x, &box.y)) { view_move_resize(view, box); @@ -398,10 +398,10 @@ view_maximize(struct view *view, bool maximize) } if (maximize) { interactive_end(view); - view->unmaximized_geometry.x = view->x; - view->unmaximized_geometry.y = view->y; - view->unmaximized_geometry.width = view->w; - view->unmaximized_geometry.height = view->h; + view->natural_geometry.x = view->x; + view->natural_geometry.y = view->y; + view->natural_geometry.width = view->w; + view->natural_geometry.height = view->h; view_apply_maximized_geometry(view); view->maximized = true; @@ -494,10 +494,10 @@ view_set_fullscreen(struct view *view, bool fullscreen, } if (fullscreen) { if (!view->maximized) { - view->unmaximized_geometry.x = view->x; - view->unmaximized_geometry.y = view->y; - view->unmaximized_geometry.width = view->w; - view->unmaximized_geometry.height = view->h; + view->natural_geometry.x = view->x; + view->natural_geometry.y = view->y; + view->natural_geometry.width = view->w; + view->natural_geometry.height = view->h; } view->fullscreen = wlr_output; view_apply_fullscreen_geometry(view, view->fullscreen); From 3c345201cd62af482b91a2f227fa5457846e0999 Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Fri, 1 Jul 2022 20:42:41 +0200 Subject: [PATCH 12/16] Restore original geometry when moving a tiled window Fixes #391 --- src/interactive.c | 38 +++++++++++++++++++++++++++++--------- src/view.c | 30 ++++++++++++++++++------------ 2 files changed, 47 insertions(+), 21 deletions(-) diff --git a/src/interactive.c b/src/interactive.c index c4dde0cc..d0d8f808 100644 --- a/src/interactive.c +++ b/src/interactive.c @@ -17,29 +17,49 @@ max_move_scale(double pos_cursor, double pos_current, void interactive_begin(struct view *view, enum input_mode mode, uint32_t edges) { - if (view->maximized) { + if (mode == LAB_INPUT_STATE_MOVE && view->fullscreen) { + /** + * We don't allow moving fullscreen windows. + * + * If you think there is a good reason to allow it + * feel free to open an issue explaining your use-case. + */ + return; + } + if (mode == LAB_INPUT_STATE_RESIZE + && (view->fullscreen || view->maximized)) { + /* We don't allow resizing while in maximized or fullscreen state */ + return; + } + if (view->maximized || view->tiled) { if (mode == LAB_INPUT_STATE_MOVE) { + /* Exit maximized or tiled mode */ int new_x = max_move_scale(view->server->seat.cursor->x, view->x, view->w, view->natural_geometry.width); int new_y = max_move_scale(view->server->seat.cursor->y, view->y, view->h, view->natural_geometry.height); view->natural_geometry.x = new_x; view->natural_geometry.y = new_y; - view_maximize(view, false); - /* - * view_maximize() indirectly calls view->impl->configure - * which is async but we are using the current values in - * server->grab_box. We pretend the configure already - * happened by setting them manually. + if (view->maximized) { + view_maximize(view, false); + } + if (view->tiled) { + view_move_resize(view, view->natural_geometry); + } + /** + * view_maximize() / view_move_resize() indirectly calls + * view->impl->configure which is async but we are using + * the current values in server->grab_box. We pretend the + * configure already happened by setting them manually. */ view->x = new_x; view->y = new_y; view->w = view->natural_geometry.width; view->h = view->natural_geometry.height; - } else { - return; } } + + /* Moving or resizing always resets tiled state */ view->tiled = 0; /* diff --git a/src/view.c b/src/view.c index af291228..b833c372 100644 --- a/src/view.c +++ b/src/view.c @@ -215,6 +215,15 @@ view_wlr_output(struct view *view) return wlr_output; } +static void +view_store_natural_geometry(struct view *view) +{ + view->natural_geometry.x = view->x; + view->natural_geometry.y = view->y; + view->natural_geometry.width = view->w; + view->natural_geometry.height = view->h; +} + static struct output * view_output(struct view *view) { @@ -398,11 +407,9 @@ view_maximize(struct view *view, bool maximize) } if (maximize) { interactive_end(view); - view->natural_geometry.x = view->x; - view->natural_geometry.y = view->y; - view->natural_geometry.width = view->w; - view->natural_geometry.height = view->h; - + if (!view->tiled) { + view_store_natural_geometry(view); + } view_apply_maximized_geometry(view); view->maximized = true; } else { @@ -493,11 +500,8 @@ view_set_fullscreen(struct view *view, bool fullscreen, wlr_output = view_wlr_output(view); } if (fullscreen) { - if (!view->maximized) { - view->natural_geometry.x = view->x; - view->natural_geometry.y = view->y; - view->natural_geometry.width = view->w; - view->natural_geometry.height = view->h; + if (!view->maximized && !view->tiled) { + view_store_natural_geometry(view); } view->fullscreen = wlr_output; view_apply_fullscreen_geometry(view, view->fullscreen); @@ -710,10 +714,12 @@ view_snap_to_edge(struct view *view, const char *direction) } if (view->maximized) { + /* Unmaximize + keep using existing natural_geometry */ view_maximize(view, false); + } else if (!view->tiled) { + /* store current geometry as new natural_geometry */ + view_store_natural_geometry(view); } - - /* TODO: store old geometry if !maximized && !fullscreen && !tiled */ view->tiled = edge; view_apply_tiled_geometry(view, output); } From 80792d446f64a7ed01b04e39e11018b904413533 Mon Sep 17 00:00:00 2001 From: John Lindgren Date: Sat, 2 Jul 2022 13:18:31 -0400 Subject: [PATCH 13/16] (Partly) fix handling of client-initiated configure requests - Add missing call to wlr_scene_node_set_position() in unmanaged_handle_commit() -- this fixes moving unmanaged XWayland windows. - Update view->pending_move_resize when we receive a configure request for a managed XWayland surface -- this fixes moving managed but undecorated XWayland windows. - Also update view->pending_move_resize when we move a surface while a configure request is already pending -- this fixes a discrepancy between displayed and actual position for XWayland windows that try to set their own initial position, but then get overridden by labwc's positioning. Moving undecorated XWayland windows is still really glitchy -- it appears that an XWayland window gets sent incorrect mouse motion coordinates when there is a pending configure request moving the window itself. --- include/labwc.h | 1 + src/xwayland-unmanaged.c | 7 +++++-- src/xwayland.c | 14 ++++++++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/include/labwc.h b/include/labwc.h index 7dd863bd..0af693ea 100644 --- a/include/labwc.h +++ b/include/labwc.h @@ -365,6 +365,7 @@ struct view { struct xwayland_unmanaged { struct server *server; struct wlr_xwayland_surface *xwayland_surface; + struct wlr_scene_node *node; struct wl_list link; int lx, ly; diff --git a/src/xwayland-unmanaged.c b/src/xwayland-unmanaged.c index 68fe4a0a..fae8d0ba 100644 --- a/src/xwayland-unmanaged.c +++ b/src/xwayland-unmanaged.c @@ -20,6 +20,8 @@ unmanaged_handle_commit(struct wl_listener *listener, void *data) struct wlr_xwayland_surface *xsurface = unmanaged->xwayland_surface; unmanaged->lx = xsurface->x; unmanaged->ly = xsurface->y; + wlr_scene_node_set_position(unmanaged->node, + unmanaged->lx, unmanaged->ly); } static void @@ -59,10 +61,11 @@ unmanaged_handle_map(struct wl_listener *listener, void *data) } /* node will be destroyed automatically once surface is destroyed */ - struct wlr_scene_node *node = &wlr_scene_surface_create( + unmanaged->node = &wlr_scene_surface_create( unmanaged->server->unmanaged_tree, xsurface->surface)->buffer->node; - wlr_scene_node_set_position(node, unmanaged->lx, unmanaged->ly); + wlr_scene_node_set_position(unmanaged->node, + unmanaged->lx, unmanaged->ly); } static void diff --git a/src/xwayland.c b/src/xwayland.c index 1efd4415..37cf4c0e 100644 --- a/src/xwayland.c +++ b/src/xwayland.c @@ -144,6 +144,13 @@ handle_request_configure(struct wl_listener *listener, void *data) int height = event->height; view_adjust_size(view, &width, &height); + view->pending_move_resize.update_x = event->x != view->x; + view->pending_move_resize.update_y = event->y != view->y; + view->pending_move_resize.x = event->x; + view->pending_move_resize.y = event->y; + view->pending_move_resize.width = width; + view->pending_move_resize.height = height; + wlr_xwayland_surface_configure(view->xwayland_surface, event->x, event->y, width, height); } @@ -216,6 +223,13 @@ move(struct view *view, double x, double y) { view->x = x; view->y = y; + + /* override any previous pending move */ + view->pending_move_resize.update_x = false; + view->pending_move_resize.update_y = false; + view->pending_move_resize.x = x; + view->pending_move_resize.y = y; + struct wlr_xwayland_surface *s = view->xwayland_surface; wlr_xwayland_surface_configure(s, (int16_t)x, (int16_t)y, (uint16_t)s->width, (uint16_t)s->height); From baaee2693736ee50ee11246fd202b5cf16e607fe Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Sat, 2 Jul 2022 20:23:14 +0200 Subject: [PATCH 14/16] src/view.c: Fall back to default geometry when changing state This makes sure that applications starting in maximized of fullscreen mode always have their natural_geometry set to sensible values. Partly fixes #403 --- src/view.c | 67 +++++++++++++++++++++++++++--------------------------- 1 file changed, 34 insertions(+), 33 deletions(-) diff --git a/src/view.c b/src/view.c index b833c372..6288d671 100644 --- a/src/view.c +++ b/src/view.c @@ -8,6 +8,8 @@ #include "menu/menu.h" #include "workspaces.h" +#define LAB_FALLBACK_WIDTH 640 +#define LAB_FALLBACK_HEIGHT 480 #define MAX(a, b) (((a) > (b)) ? (a) : (b)) /** @@ -215,15 +217,6 @@ view_wlr_output(struct view *view) return wlr_output; } -static void -view_store_natural_geometry(struct view *view) -{ - view->natural_geometry.x = view->x; - view->natural_geometry.y = view->y; - view->natural_geometry.width = view->w; - view->natural_geometry.height = view->h; -} - static struct output * view_output(struct view *view) { @@ -268,6 +261,38 @@ view_compute_centered_position(struct view *view, int w, int h, int *x, int *y) return true; } +static void +set_fallback_geometry(struct view *view) +{ + view->natural_geometry.width = LAB_FALLBACK_WIDTH; + view->natural_geometry.height = LAB_FALLBACK_HEIGHT; + view_compute_centered_position(view, + view->natural_geometry.width, + view->natural_geometry.height, + &view->natural_geometry.x, + &view->natural_geometry.y); +} +#undef LAB_FALLBACK_WIDTH +#undef LAB_FALLBACK_HEIGHT + +static void +view_store_natural_geometry(struct view *view) +{ + /** + * If an application was started maximized or fullscreened, its + * natural_geometry width/height may still be zero in which case we set + * some fallback values. This is the case with foot and Qt applications. + */ + if (!view->w || !view->h) { + set_fallback_geometry(view); + } else { + view->natural_geometry.x = view->x; + view->natural_geometry.y = view->y; + view->natural_geometry.width = view->w; + view->natural_geometry.height = view->h; + } +} + void view_center(struct view *view) { @@ -347,33 +372,9 @@ view_apply_maximized_geometry(struct view *view) view_move_resize(view, box); } -#define LAB_FALLBACK_WIDTH (640) -#define LAB_FALLBACK_HEIGHT (480) - -static void -set_fallback_geometry(struct view *view) -{ - view->natural_geometry.width = LAB_FALLBACK_WIDTH; - view->natural_geometry.height = LAB_FALLBACK_HEIGHT; - view_compute_centered_position(view, - view->natural_geometry.width, - view->natural_geometry.height, - &view->natural_geometry.x, - &view->natural_geometry.y); -} - static void view_apply_unmaximized_geometry(struct view *view) { - /* - * If an application was started maximized, its unmaximized_geometry - * width/height may still be zero in which case we set some fallback - * values. This is the case with foot and Qt applications. - */ - if (wlr_box_empty(&view->natural_geometry)) { - set_fallback_geometry(view); - } - struct wlr_output_layout *layout = view->server->output_layout; if (wlr_output_layout_intersects(layout, NULL, &view->natural_geometry)) { From 9b49f19a7315d2a6735a49156f6e71a9aff08f96 Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Fri, 10 Jun 2022 19:42:34 +0200 Subject: [PATCH 15/16] src/action.c: Convert action->arg to a list of action_arg In preperation for Actions that require multiple arguments --- include/action.h | 18 +++--- include/config/keybind.h | 4 +- include/config/mousebind.h | 4 +- include/config/rcxml.h | 6 +- include/private/action.h | 24 ++++++++ src/action.c | 117 ++++++++++++++++++++++++++++--------- src/config/rcxml.c | 24 +++----- src/menu/menu.c | 6 +- 8 files changed, 142 insertions(+), 61 deletions(-) create mode 100644 include/private/action.h diff --git a/include/action.h b/include/action.h index b23a0ec9..e5506033 100644 --- a/include/action.h +++ b/include/action.h @@ -2,19 +2,23 @@ #ifndef __LABWC_ACTION_H #define __LABWC_ACTION_H -struct server; struct view; +struct server; +struct wl_list; struct action { - uint32_t type; - char *arg; - struct wl_list link; + struct wl_list link; /* struct keybinding.actions, + * struct mousebinding.actions, + * struct menuitem.actions */ + + uint32_t type; /* enum action_type */ + struct wl_list args; /* struct action_arg.link */ }; struct action *action_create(const char *action_name); -void action_list_free(struct wl_list *action_list); - +void action_arg_add_str(struct action *action, char *key, const char *value); void actions_run(struct view *activator, struct server *server, struct wl_list *actions, uint32_t resize_edges); +void action_list_free(struct wl_list *action_list); -#endif +#endif /* __LABWC_ACTION_H */ diff --git a/include/config/keybind.h b/include/config/keybind.h index 86eb4b52..b11914ed 100644 --- a/include/config/keybind.h +++ b/include/config/keybind.h @@ -11,8 +11,8 @@ struct keybind { uint32_t modifiers; xkb_keysym_t *keysyms; size_t keysyms_len; - struct wl_list actions; - struct wl_list link; + struct wl_list actions; /* struct action.link */ + struct wl_list link; /* struct rcxml.keybinds */ }; /** diff --git a/include/config/mousebind.h b/include/config/mousebind.h index ae66532a..af73dd4f 100644 --- a/include/config/mousebind.h +++ b/include/config/mousebind.h @@ -26,9 +26,9 @@ struct mousebind { /* ex: doubleclick, press, drag */ enum mouse_event mouse_event; - struct wl_list actions; + struct wl_list actions; /* struct action.link */ - struct wl_list link; /* rcxml::mousebinds */ + struct wl_list link; /* struct rcxml.mousebinds */ bool pressed_in_context; /* used in click events */ }; diff --git a/include/config/rcxml.h b/include/config/rcxml.h index 41382de2..5827f51a 100644 --- a/include/config/rcxml.h +++ b/include/config/rcxml.h @@ -37,11 +37,11 @@ struct rcxml { /* keyboard */ int repeat_rate; int repeat_delay; - struct wl_list keybinds; + struct wl_list keybinds; /* struct keybind.link */ /* mouse */ - long doubleclick_time; /* in ms */ - struct wl_list mousebinds; + long doubleclick_time; /* in ms */ + struct wl_list mousebinds; /* struct mousebind.link */ /* libinput */ struct wl_list libinput_categories; diff --git a/include/private/action.h b/include/private/action.h new file mode 100644 index 00000000..0b8f60d0 --- /dev/null +++ b/include/private/action.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __LABWC_PRIVATE_ACTION_H +#define __LABWC_PRIVATE_ACTION_H + +/* Don't include ourself as search path starts at current directory */ +#include "../action.h" + +enum action_arg_type { + LAB_ACTION_ARG_STR = 0, +}; + +struct action_arg { + struct wl_list link; /* struct action.args */ + + const char *key; /* May be NULL if there is just one arg */ + enum action_arg_type type; +}; + +struct action_arg_str { + struct action_arg base; + char *value; +}; + +#endif /* __LABWC_PRIVATE_ACTION_H */ diff --git a/src/action.c b/src/action.c index d29048fb..3b6dd4d4 100644 --- a/src/action.c +++ b/src/action.c @@ -1,6 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only #define _POSIX_C_SOURCE 200809L +#include #include +#include #include #include #include @@ -9,8 +11,8 @@ #include "debug.h" #include "labwc.h" #include "menu/menu.h" +#include "private/action.h" #include "ssd.h" -#include "action.h" #include "workspaces.h" enum action_type { @@ -64,6 +66,24 @@ const char *action_names[] = { NULL }; +static char * +action_str_from_arg(struct action_arg *arg) +{ + assert(arg->type == LAB_ACTION_ARG_STR); + return ((struct action_arg_str *)arg)->value; +} + +static struct action_arg * +action_get_first_arg(struct action *action) +{ + struct action_arg *arg; + struct wl_list *item = action->args.next; + if (item == &action->args) { + return NULL; + } + return wl_container_of(item, arg, link); +} + static enum action_type action_type_from_str(const char *action_name) { @@ -85,15 +105,26 @@ action_create(const char *action_name) } struct action *action = calloc(1, sizeof(struct action)); action->type = action_type_from_str(action_name); + wl_list_init(&action->args); return action; } void action_list_free(struct wl_list *action_list) { + struct action_arg *arg, *arg_tmp; struct action *action, *action_tmp; + /* Free actions */ wl_list_for_each_safe(action, action_tmp, action_list, link) { wl_list_remove(&action->link); - zfree(action->arg); + /* Free args */ + wl_list_for_each_safe(arg, arg_tmp, &action->args, link) { + wl_list_remove(&arg->link); + zfree(arg->key); + if (arg->type == LAB_ACTION_ARG_STR) { + free(action_str_from_arg(arg)); + } + zfree(arg); + } zfree(action); } } @@ -151,9 +182,13 @@ actions_run(struct view *activator, struct server *server, struct view *view; struct action *action; + struct action_arg *arg; wl_list_for_each(action, actions, link) { - wlr_log(WLR_DEBUG, "Handling action %s (%u) with arg %s", - action_names[action->type], action->type, action->arg); + wlr_log(WLR_DEBUG, "Handling action %s (%u)", + action_names[action->type], action->type); + + /* Get arg now so we don't have to repeat every time we only need one */ + arg = action_get_first_arg(action); /* * Refetch view because it may have been changed due to the @@ -171,28 +206,30 @@ actions_run(struct view *activator, struct server *server, debug_dump_scene(server); break; case ACTION_TYPE_EXECUTE: - { - struct buf cmd; - buf_init(&cmd); - buf_add(&cmd, action->arg); - buf_expand_shell_variables(&cmd); - spawn_async_no_shell(cmd.buf); - free(cmd.buf); + if (!arg) { + wlr_log(WLR_ERROR, "Missing argument for Execute"); + break; } + struct buf cmd; + buf_init(&cmd); + buf_add(&cmd, action_str_from_arg(arg)); + buf_expand_shell_variables(&cmd); + spawn_async_no_shell(cmd.buf); + free(cmd.buf); break; case ACTION_TYPE_EXIT: wl_display_terminate(server->wl_display); break; case ACTION_TYPE_MOVE_TO_EDGE: - if (action->arg) { - view_move_to_edge(view, action->arg); + if (arg) { + view_move_to_edge(view, action_str_from_arg(arg)); } else { wlr_log(WLR_ERROR, "Missing argument for MoveToEdge"); } break; case ACTION_TYPE_SNAP_TO_EDGE: - if (action->arg) { - view_snap_to_edge(view, action->arg); + if (arg) { + view_snap_to_edge(view, action_str_from_arg(arg)); } else { wlr_log(WLR_ERROR, "Missing argument for SnapToEdge"); } @@ -211,7 +248,11 @@ actions_run(struct view *activator, struct server *server, kill(getpid(), SIGHUP); break; case ACTION_TYPE_SHOW_MENU: - show_menu(server, view, action->arg); + if (arg) { + show_menu(server, view, action_str_from_arg(arg)); + } else { + wlr_log(WLR_ERROR, "Missing argument for ShowMenu"); + } break; case ACTION_TYPE_TOGGLE_MAXIMIZE: if (view) { @@ -263,27 +304,33 @@ actions_run(struct view *activator, struct server *server, } break; case ACTION_TYPE_GO_TO_DESKTOP: - { - struct workspace *target; - target = workspaces_find(server->workspace_current, action->arg); - if (target) { - workspaces_switch_to(target); - } + if (!arg) { + wlr_log(WLR_ERROR, "Missing argument for GoToDesktop"); + break; + } + struct workspace *target; + char *target_name = action_str_from_arg(arg); + target = workspaces_find(server->workspace_current, target_name); + if (target) { + workspaces_switch_to(target); } break; case ACTION_TYPE_SEND_TO_DESKTOP: + if (!arg) { + wlr_log(WLR_ERROR, "Missing argument for SendToDesktop"); + break; + } if (view) { struct workspace *target; - target = workspaces_find(view->workspace, action->arg); + char *target_name = action_str_from_arg(arg); + target = workspaces_find(view->workspace, target_name); if (target) { workspaces_send_to(view, target); } } break; case ACTION_TYPE_NONE: - wlr_log(WLR_ERROR, - "Not executing unknown action with arg %s", - action->arg); + wlr_log(WLR_ERROR, "Not executing unknown action"); break; default: /* @@ -292,9 +339,21 @@ actions_run(struct view *activator, struct server *server, * adding a new action without installing a handler here. */ wlr_log(WLR_ERROR, - "Not executing invalid action (%u) with arg %s" - " This is a BUG. Please report.", - action->type, action->arg); + "Not executing invalid action (%u)" + " This is a BUG. Please report.", action->type); } } } + +void +action_arg_add_str(struct action *action, char *key, const char *value) +{ + assert(value && "Tried to add NULL action string argument"); + struct action_arg_str *arg = calloc(1, sizeof(*arg)); + arg->base.type = LAB_ACTION_ARG_STR; + if (key) { + arg->base.key = strdup(key); + } + arg->value = strdup(value); + wl_list_insert(action->args.prev, &arg->base.link); +} diff --git a/src/config/rcxml.c b/src/config/rcxml.c index 19bd2133..1d950f7a 100644 --- a/src/config/rcxml.c +++ b/src/config/rcxml.c @@ -71,21 +71,18 @@ fill_keybind(char *nodename, char *content) } else if (!current_keybind_action) { wlr_log(WLR_ERROR, "expect element first. " "nodename: '%s' content: '%s'", nodename, content); - } else if (current_keybind_action->arg) { - wlr_log(WLR_ERROR, "Action argument already set: %s", - current_keybind_action->arg); } else if (!strcmp(nodename, "command.action")) { /* Execute */ - current_keybind_action->arg = strdup(content); + action_arg_add_str(current_keybind_action, NULL, content); } else if (!strcmp(nodename, "direction.action")) { /* MoveToEdge, SnapToEdge */ - current_keybind_action->arg = strdup(content); + action_arg_add_str(current_keybind_action, NULL, content); } else if (!strcmp(nodename, "menu.action")) { /* ShowMenu */ - current_keybind_action->arg = strdup(content); + action_arg_add_str(current_keybind_action, NULL, content); } else if (!strcmp(nodename, "to.action")) { /* GoToDesktop, SendToDesktop */ - current_keybind_action->arg = strdup(content); + action_arg_add_str(current_keybind_action, NULL, content); } } @@ -134,15 +131,12 @@ fill_mousebind(char *nodename, char *content) } else if (!current_mousebind_action) { wlr_log(WLR_ERROR, "expect element first. " "nodename: '%s' content: '%s'", nodename, content); - } else if (current_mousebind_action->arg) { - wlr_log(WLR_ERROR, "Action argument already set: %s", - current_mousebind_action->arg); } else if (!strcmp(nodename, "command.action")) { - current_mousebind_action->arg = strdup(content); + action_arg_add_str(current_mousebind_action, NULL, content); } else if (!strcmp(nodename, "direction.action")) { - current_mousebind_action->arg = strdup(content); + action_arg_add_str(current_mousebind_action, NULL, content); } else if (!strcmp(nodename, "menu.action")) { - current_mousebind_action->arg = strdup(content); + action_arg_add_str(current_mousebind_action, NULL, content); } } @@ -544,7 +538,7 @@ load_default_key_bindings(void) wl_list_insert(k->actions.prev, &action->link); if (key_combos[i].command) { - action->arg = strdup(key_combos[i].command); + action_arg_add_str(action, NULL, key_combos[i].command); } } } @@ -604,7 +598,7 @@ load_default_mouse_bindings(void) wl_list_insert(m->actions.prev, &action->link); if (mouse_combos[i].command) { - action->arg = strdup(mouse_combos[i].command); + action_arg_add_str(action, NULL, mouse_combos[i].command); } } } diff --git a/src/menu/menu.c b/src/menu/menu.c index bb79295e..a2677c8b 100644 --- a/src/menu/menu.c +++ b/src/menu/menu.c @@ -238,16 +238,16 @@ fill_item(char *nodename, char *content) wlr_log(WLR_ERROR, "expect element first. " "nodename: '%s' content: '%s'", nodename, content); } else if (!strcmp(nodename, "command.action")) { - current_item_action->arg = strdup(content); + action_arg_add_str(current_item_action, NULL, content); } else if (!strcmp(nodename, "execute.action")) { /* * foo * is deprecated, but we support it anyway for backward * compatibility with old openbox-menu generators */ - current_item_action->arg = strdup(content); + action_arg_add_str(current_item_action, NULL, content); } else if (!strcmp(nodename, "to.action")) { - current_item_action->arg = strdup(content); + action_arg_add_str(current_item_action, NULL, content); } } From bfff9d02c717ad1a9b3693a843dd267774cdc7e9 Mon Sep 17 00:00:00 2001 From: Johan Malm Date: Mon, 4 Jul 2022 18:25:52 +0100 Subject: [PATCH 16/16] xwayland.c: fix position bug Set node position in the configure/set_geometry handlers when moving a window in response to a client request. Steps to reproduce weird positioning fixed by this patch: 1. Start leafpad 2. Open Help->About 3. Move the dialog 4. Close the dialog 5. Open it again 6. Drag it and observe a jump in position There is also an xwayland PyQt5 script in PR #428 which demonstrates jumpy position. --- src/xwayland-unmanaged.c | 2 ++ src/xwayland.c | 1 + 2 files changed, 3 insertions(+) diff --git a/src/xwayland-unmanaged.c b/src/xwayland-unmanaged.c index fae8d0ba..4c68223b 100644 --- a/src/xwayland-unmanaged.c +++ b/src/xwayland-unmanaged.c @@ -35,6 +35,8 @@ unmanaged_handle_set_geometry(struct wl_listener *listener, void *data) wlr_log(WLR_DEBUG, "xwayland-unmanaged surface has moved"); unmanaged->lx = xsurface->x; unmanaged->ly = xsurface->y; + wlr_scene_node_set_position(unmanaged->node, + unmanaged->lx, unmanaged->ly); } } diff --git a/src/xwayland.c b/src/xwayland.c index 37cf4c0e..9c516433 100644 --- a/src/xwayland.c +++ b/src/xwayland.c @@ -151,6 +151,7 @@ handle_request_configure(struct wl_listener *listener, void *data) view->pending_move_resize.width = width; view->pending_move_resize.height = height; + wlr_scene_node_set_position(&view->scene_tree->node, event->x, event->y); wlr_xwayland_surface_configure(view->xwayland_surface, event->x, event->y, width, height); }