Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package labwc for openSUSE:Factory checked 
in at 2026-08-22 21:35:34
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/labwc (Old)
 and      /work/SRC/openSUSE:Factory/.labwc.new.1258 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "labwc"

Sat Aug 22 21:35:34 2026 rev:19 rq:1373020 version:0.20.2

Changes:
--------
--- /work/SRC/openSUSE:Factory/labwc/labwc.changes      2026-06-16 
18:30:36.084553525 +0200
+++ /work/SRC/openSUSE:Factory/.labwc.new.1258/labwc.changes    2026-08-22 
21:37:41.816551630 +0200
@@ -1,0 +2,15 @@
+Fri Aug 21 18:34:01 UTC 2026 - zeus <[email protected]>
+
+- Update to version 0.20.2:
+  * Display config errors in labnag or optionally another client. 
+  Also support associated option <core><errorCommand>
+  * Destroy scene-output before scene cleanup to avoid rare abort.
+  * Do not leave a failed output render format on the pending state
+  * When window-cycling is cancelled give back focus to the window
+  that had it before cycling started
+  * Fix missing panel icon with Firefox running under X11
+  * abnag(1): document defaults
+  * Force the initial modeset commit to fix an issue with 
+  QEMU/virtio-gpu and WLR_NO_HARDWARE_CURSORS=1
+
+-------------------------------------------------------------------

Old:
----
  labwc-0.20.1.tar.gz

New:
----
  labwc-0.20.2.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ labwc.spec ++++++
--- /var/tmp/diff_new_pack.QdmMDm/_old  2026-08-22 21:37:42.389572113 +0200
+++ /var/tmp/diff_new_pack.QdmMDm/_new  2026-08-22 21:37:42.391572184 +0200
@@ -24,7 +24,7 @@
 %define slname  libsfdo
 %define slver   0.1.4
 Name:           labwc
-Version:        0.20.1
+Version:        0.20.2
 Release:        0
 Summary:        A Wayland window-stacking compositor
 License:        GPL-2.0-only

++++++ labwc-0.20.1.tar.gz -> labwc-0.20.2.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/labwc-0.20.1/NEWS.md new/labwc-0.20.2/NEWS.md
--- old/labwc-0.20.1/NEWS.md    2026-06-15 20:43:52.000000000 +0200
+++ new/labwc-0.20.2/NEWS.md    2026-08-21 19:24:33.000000000 +0200
@@ -9,6 +9,7 @@
 
 | Date       | All Changes   | wlroots version | lines-of-code |
 |------------|---------------|-----------------|---------------|
+| 2026-08-21 | [0.20.2]      | 0.20.2          | 28553         |
 | 2026-06-15 | [0.20.1]      | 0.20.1          | 28337         |
 | 2026-05-25 | [0.20.0]      | 0.20.1          | 28313         |
 | 2026-06-11 | [0.9.8]       | 0.19.3          | 29284         |
@@ -47,6 +48,7 @@
 | 2021-03-05 | [0.1.0]       | 0.12.0          | 4627          |
 
 [unreleased]: NEWS.md#unreleased
+[0.20.2]: NEWS.md#0202---2026-08-21
 [0.20.1]: NEWS.md#0201---2026-06-15
 [0.20.0]: NEWS.md#0200---2026-05-25
 [0.9.8]: NEWS.md#098---2026-06-11
@@ -92,14 +94,39 @@
 
 There are some regression warnings worth noting for the switch to wlroots 0.20:
 
-- lxqt-panel auto-hiding does not work with a panel size greater than 40 
[#3600]
-  [wlroots-5392]
+- With wlroots < 0.20.2 lxqt-panel auto-hiding does not work with a panel size
+  greater than 40 [#3600] [wlroots-5392] [wlroots-5407]
 - Some Wine game windows disappear after alt-tab. It is not yet clear where the
   bug is, but the issue manifests itself when running wlroots-0.20 [#3615]
   [wlroots-4103]
+- `wl_output` make/model properties are no longer sent because these are legacy
+  and should not be relied on [wlroots-5045]
 
 [wlroots-5392]: 
https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/5392
+[wlroots-5407]: 
https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/5407
 [wlroots-4103]: 
https://gitlab.freedesktop.org/wlroots/wlroots/-/work_items/4103
+[wlroots-5045]: 
https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/5045
+
+## 0.20.2 - 2026-08-21
+
+[0.20.2-commits]
+
+### Added
+
+- Display config errors in labnag or optionally another client. Also support
+  associated option `<core><errorCommand>`. @elviosak @Consolatis [#3697]
+
+### Fixed
+
+- Destroy scene-output before scene cleanup to avoid rare abort. @jlvihv 
[#3701]
+- Do not leave a failed output render format on the pending state @Andy1210
+  [#3685]
+- When window-cycling is cancelled, for example by pressing escape, give back
+  focus to the window that had it before cycling started @elviosak [#3667]
+- Fix missing panel icon with Firefox running under X11 @jlindgren90 [#3641]
+- labnag(1): document defaults @cunlem [#3654]
+- Force the initial modeset commit to fix an issue with QEMU/virtio-gpu
+  and `WLR_NO_HARDWARE_CURSORS=1`. @KiritakeKumi [#3656]
 
 ## 0.20.1 - 2026-06-15
 
@@ -1945,7 +1972,7 @@
 - Add `ToggleOmnipresent` action and add an "Always on Visible Workspace" entry
   for it in the client-menu under the Workspaces submenu. Written-by: @bnason
 - Account for space taken up by XWayland clients with `_NET_WM_STRUT_PARTIAL`
-  property in the `usable_area` calculation. This increases inter-operability
+  property in the `usable_area` calculation. This increases interoperability
   with X11 desktop components.
 - Set XWayland's `_NET_WORKAREA` property based on usable area. XWayland
   clients use the `_NET_WORKAREA` root window property to determine how much of
@@ -2813,7 +2840,8 @@
   ShowMenu
 
 [Keep a Changelog]: https://keepachangelog.com/en/1.0.0/
-[unreleased-commits]: https://github.com/labwc/labwc/compare/0.20.1...HEAD
+[unreleased-commits]: https://github.com/labwc/labwc/compare/0.20.2...HEAD
+[0.20.2-commits]: https://github.com/labwc/labwc/compare/0.20.1..0.20.2
 [0.20.1-commits]: https://github.com/labwc/labwc/compare/0.20.0..0.20.1
 [0.20.0-commits]: https://github.com/labwc/labwc/compare/0.9.5..0.20.0
 [0.9.8-commits]: https://github.com/labwc/labwc/compare/0.9.7...0.9.8
@@ -3401,3 +3429,10 @@
 [#3625]: https://github.com/labwc/labwc/pull/3625
 [#3630]: https://github.com/labwc/labwc/pull/3630
 [#3631]: https://github.com/labwc/labwc/pull/3631
+[#3641]: https://github.com/labwc/labwc/pull/3641
+[#3654]: https://github.com/labwc/labwc/pull/3654
+[#3656]: https://github.com/labwc/labwc/pull/3656
+[#3667]: https://github.com/labwc/labwc/pull/3667
+[#3685]: https://github.com/labwc/labwc/pull/3685
+[#3697]: https://github.com/labwc/labwc/pull/3697
+[#3701]: https://github.com/labwc/labwc/pull/3701
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/labwc-0.20.1/docs/labnag.1.scd 
new/labwc-0.20.2/docs/labnag.1.scd
--- old/labwc-0.20.1/docs/labnag.1.scd  2026-06-15 20:43:52.000000000 +0200
+++ new/labwc-0.20.2/docs/labnag.1.scd  2026-08-21 19:24:33.000000000 +0200
@@ -26,16 +26,16 @@
        Enable debugging.
 
 *-e, --edge* top|bottom
-       Set the edge to use.
+       Set the edge to use. Default is top.
 
 *-y, --layer* overlay|top|bottom|background
-       Set the layer to use.
+       Set the layer to use. Default is top.
 
 *-k, --keyboard-focus none|exclusive|on-demand*
-       Set the policy for keyboard focus.
+       Set the policy for keyboard focus. Default is none.
 
 *-f, --font* <font>
-       Set the font to use.
+       Set the font to use. Default is _Sans 10_.
 
 *-h, --help*
        Show help message and quit.
@@ -66,55 +66,57 @@
 # APPEARANCE OPTIONS
 
 *--background-color* <RRGGBB[AA]>
-       Set the color of the background.
+       Set the color of the background. Default is 900000.
 
 *--button-border-color* <RRGGBB[AA]>
-       Set the color of the button border.
+       Set the color of the button border. Default is D92424.
 
 *--border-bottom-color* <RRGGBB[AA]>
-       Set the color of the bottom border.
+       Set the color of the bottom border. Default is 470909.
 
 *--button-background-color* <RRGGBB[AA]>
-       Set the color for the background for buttons.
+       Set the color for the background for buttons. Default is 680A0A.
 
 *--text-color* <RRGGBB[AA]>
-       Set the text color.
+       Set the text color. Default is FFFFFF.
 
 *--button-text-color* <RRGGBB[AA]>
-       Set the button text color.
+       Set the button text color. Default is FFFFFF.
 
 *--border-bottom-size* <size>
-       Set the thickness of the bottom border.
+       Set the thickness of the bottom border. Default is 3.
 
 *--message-padding* <padding>
-       Set the padding for the message.
+       Set the padding for the message. Default is 8.
 
 *--details-background-color* <RRGGBB[AA]>
-       Set the color for the background for details.
+       Set the color for the background for details. Default is 680A0A.
 
 *--details-border-size* <size>
-       Set the thickness for the details border.
+       Set the thickness for the details border. Default is 3.
 
 *--details-border-color* <RRGGBB[AA]>
-       Set the color of the details border.
+       Set the color of the details border. Default is 680A0A.
 
 *--details-margin* <margin>
-       Set the margin for the details.
+       Set the margin for the details. Default is 11.
 
 *--button-border-size* <size>
-       Set the thickness for the button border.
+       Set the thickness for the button border. Default is 3.
 
 *--button-gap* <gap>
-       Set the size of the gap between buttons.
+       Set the size of the gap between buttons. Default is 20.
 
 *--button-dismiss-gap* <gap>
        Set the size of the gap between the dismiss button and another button.
+       Default is 15.
 
 *--button-margin-right* <margin>
        Set the margin from the right of the dismiss button to edge.
+       Default is 2.
 
 *--button-padding* <padding>
-       Set the padding for the button text.
+       Set the padding for the button text. Default is 3.
 
 # EXAMPLE
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/labwc-0.20.1/docs/labwc-actions.5.scd 
new/labwc-0.20.2/docs/labwc-actions.5.scd
--- old/labwc-0.20.1/docs/labwc-actions.5.scd   2026-06-15 20:43:52.000000000 
+0200
+++ new/labwc-0.20.2/docs/labwc-actions.5.scd   2026-08-21 19:24:33.000000000 
+0200
@@ -63,6 +63,10 @@
        top or bottom tell how much to resize on that edge of window,
        positive values grow window, negative shrink window.
 
+       Note that some applications like terminal emulators may refuse growing
+       or shrinking by small amounts to keep the window size aligned to their
+       internal cell size.
+
 *<action name="GrowToEdge" direction="value" />*
        Resize window to fill the space between its edge and any other
        window edge.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/labwc-0.20.1/docs/labwc-config.5.scd 
new/labwc-0.20.2/docs/labwc-config.5.scd
--- old/labwc-0.20.1/docs/labwc-config.5.scd    2026-06-15 20:43:52.000000000 
+0200
+++ new/labwc-0.20.2/docs/labwc-config.5.scd    2026-08-21 19:24:33.000000000 
+0200
@@ -180,6 +180,7 @@
   <xwaylandPersistence>no</xwaylandPersistence>
   <primarySelection>yes</primarySelection>
   <promptCommand>[see details below]</promptCommand>
+  <errorCommand>[see details below]</errorCommand>
 </core>
 ```
 
@@ -316,6 +317,29 @@
                --cancel-label="%n"
        ```
 
+*<core><errorCommand>*
+       Set command to be invoked for displaying errors in the config files,
+       it is executed when errors are detected on startup and reconfigure.
+       The errors are sent to STDIN of the program, and a SIGTERM is sent to
+       it if the process is still running when a reconfigure is triggered.
+
+       The default error command is:
+       ```
+       labnag \\
+               --message 'Config errors detected' \\
+               --button-dismiss 'Close' \\
+               --layer overlay \\
+               --timeout 0 \\
+               --detailed-message
+       ```
+
+       Example using `zenity`:
+       ```
+       <core>
+         <errorCommand>zenity --title='Config Error' --text-info</errorCommand>
+       </core>
+       ```
+
 ## PLACEMENT
 
 ```
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/labwc-0.20.1/docs/rc.xml.all 
new/labwc-0.20.2/docs/rc.xml.all
--- old/labwc-0.20.1/docs/rc.xml.all    2026-06-15 20:43:52.000000000 +0200
+++ new/labwc-0.20.2/docs/rc.xml.all    2026-08-21 19:24:33.000000000 +0200
@@ -20,6 +20,8 @@
     <!--
       # See labwc-config(5) for details
       <promptCommand></promptCommand>
+      # See labwc-config(5) for details
+      <errorCommand></errorCommand>
     -->
   </core>
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/labwc-0.20.1/include/common/nag.h 
new/labwc-0.20.2/include/common/nag.h
--- old/labwc-0.20.1/include/common/nag.h       1970-01-01 01:00:00.000000000 
+0100
+++ new/labwc-0.20.2/include/common/nag.h       2026-08-21 19:24:33.000000000 
+0200
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef LABWC_NAG_H
+#define LABWC_NAG_H
+
+#include <stdbool.h>
+#include <sys/wait.h>
+#include <wlr/util/log.h>
+#include "common/buf.h"
+
+/* May return NULL if the buffer is currently written to a client */
+struct buf *nag_get_buf(void);
+
+void nag_set_error(enum wlr_log_importance importance);
+bool nag_check_pid(pid_t exited_pid);
+void nag_reset(void);
+void nag_show_callback(void *data);
+void nag_finish(void);
+
+#define nag_log(verbosity, fmt, ...) \
+do { \
+       wlr_log(verbosity, fmt, ##__VA_ARGS__); \
+       nag_set_error(verbosity); \
+       if (nag_get_buf()) { \
+               buf_add_fmt(nag_get_buf(), fmt "\n", ##__VA_ARGS__); \
+       } \
+} while (0)
+
+#endif /* LABWC_NAG_H */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/labwc-0.20.1/include/common/spawn.h 
new/labwc-0.20.2/include/common/spawn.h
--- old/labwc-0.20.1/include/common/spawn.h     2026-06-15 20:43:52.000000000 
+0200
+++ new/labwc-0.20.2/include/common/spawn.h     2026-08-21 19:24:33.000000000 
+0200
@@ -23,6 +23,19 @@
 void spawn_sync_no_shell(char const *command);
 
 /**
+ * spawn_piped_async_no_shell - execute asynchronously
+ * @command: command to be executed
+ * @pipe_fd_w: set to the write end of a pipe
+ *             connected to stdin of the command
+ * Notes:
+ * The returned pid_t has to be waited for to
+ * not produce zombies and the pipe_fd_w has to
+ * be closed. spawn_piped_close() can be used
+ * to ensure both.
+ */
+pid_t spawn_piped_async_no_shell(const char *command, int *pipe_fd_w);
+
+/**
  * spawn_piped - execute asynchronously
  * @command: command to be executed
  * @pipe_fd: set to the read end of a pipe
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/labwc-0.20.1/include/config/rcxml.h 
new/labwc-0.20.2/include/config/rcxml.h
--- old/labwc-0.20.1/include/config/rcxml.h     2026-06-15 20:43:52.000000000 
+0200
+++ new/labwc-0.20.2/include/config/rcxml.h     2026-08-21 19:24:33.000000000 
+0200
@@ -87,6 +87,7 @@
        bool xwayland_persistence;
        bool primary_selection;
        char *prompt_command;
+       char *error_command;
 
        /* placement */
        enum lab_placement_policy placement_policy;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/labwc-0.20.1/meson.build new/labwc-0.20.2/meson.build
--- old/labwc-0.20.1/meson.build        2026-06-15 20:43:52.000000000 +0200
+++ new/labwc-0.20.2/meson.build        2026-08-21 19:24:33.000000000 +0200
@@ -1,7 +1,7 @@
 project(
   'labwc',
   'c',
-  version: '0.20.1',
+  version: '0.20.2',
   license: 'GPL-2.0-only',
   meson_version: '>=0.59.0',
   default_options: [
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/labwc-0.20.1/po/LINGUAS new/labwc-0.20.2/po/LINGUAS
--- old/labwc-0.20.1/po/LINGUAS 2026-06-15 20:43:52.000000000 +0200
+++ new/labwc-0.20.2/po/LINGUAS 2026-08-21 19:24:33.000000000 +0200
@@ -1 +1 @@
-ar ca cs da de el es et eu fa fi fr gl he hr hu id it ja ka kab kk ko lt ms nl 
pa pl pt pt_BR ru sk sr_Latn sv tr uk vi zh_CN zh_TW
+ar ca cs da de el es et eu fa fi fr gl he hr hu id it ja ka kab kk ko lt ms nl 
pa pl pt pt_BR ru sk sr_Latn sv te tr uk vi zh_CN zh_TW
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/labwc-0.20.1/po/el.po new/labwc-0.20.2/po/el.po
--- old/labwc-0.20.1/po/el.po   2026-06-15 20:43:52.000000000 +0200
+++ new/labwc-0.20.2/po/el.po   2026-08-21 19:24:33.000000000 +0200
@@ -8,7 +8,7 @@
 "Project-Id-Version: labwc\n"
 "Report-Msgid-Bugs-To: https://github.com/labwc/labwc/issues\n";
 "POT-Creation-Date: 2024-09-19 21:09+1000\n"
-"PO-Revision-Date: 2025-08-02 08:01+0000\n"
+"PO-Revision-Date: 2026-07-14 03:29+0000\n"
 "Last-Translator: Dimitrios Glentadakis <[email protected]>\n"
 "Language-Team: Greek <https://translate.lxqt-project.org/projects/labwc/";
 "labwc/el/>\n"
@@ -21,7 +21,7 @@
 
 #: src/menu/menu.c:1016
 msgid "Go there..."
-msgstr "Πήγαινε εκεί..."
+msgstr "Πήγαινε..."
 
 #: src/menu/menu.c:1034
 msgid "Terminal"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/labwc-0.20.1/po/id.po new/labwc-0.20.2/po/id.po
--- old/labwc-0.20.1/po/id.po   2026-06-15 20:43:52.000000000 +0200
+++ new/labwc-0.20.2/po/id.po   2026-08-21 19:24:33.000000000 +0200
@@ -8,9 +8,10 @@
 "Project-Id-Version: labwc\n"
 "Report-Msgid-Bugs-To: https://github.com/labwc/labwc/issues\n";
 "POT-Creation-Date: 2024-09-19 21:09+1000\n"
-"PO-Revision-Date: 2025-05-02 13:26+0000\n"
-"Last-Translator: Syahmin Sukhairi <[email protected]>\n"
-"Language-Team: Indonesian 
<https://translate.lxqt-project.org/projects/labwc/labwc/id/>\n"
+"PO-Revision-Date: 2026-07-27 07:29+0000\n"
+"Last-Translator: Zycresth <[email protected]>\n"
+"Language-Team: Indonesian <https://translate.lxqt-project.org/projects/labwc/";
+"labwc/id/>\n"
 "Language: id\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
@@ -24,7 +25,7 @@
 
 #: src/menu/menu.c:1034
 msgid "Terminal"
-msgstr ""
+msgstr "Terminal"
 
 #: src/menu/menu.c:1040
 msgid "Reconfigure"
@@ -48,7 +49,7 @@
 
 #: src/menu/menu.c:1062
 msgid "Roll Up/Down"
-msgstr "Gulir atas/bawah"
+msgstr "Gulir Atas/Bawah"
 
 #: src/menu/menu.c:1064
 msgid "Decorations"
@@ -56,15 +57,15 @@
 
 #: src/menu/menu.c:1066
 msgid "Always on Top"
-msgstr "Selalu di Muka"
+msgstr "Selalu di Atas"
 
 #: src/menu/menu.c:1071
 msgid "Move Left"
-msgstr "Geser ke Kiri"
+msgstr "Geser Kiri"
 
 #: src/menu/menu.c:1078
 msgid "Move Right"
-msgstr "Geser ke Kanan"
+msgstr "Geser Kanan"
 
 #: src/menu/menu.c:1083
 msgid "Always on Visible Workspace"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/labwc-0.20.1/po/te.po new/labwc-0.20.2/po/te.po
--- old/labwc-0.20.1/po/te.po   1970-01-01 01:00:00.000000000 +0100
+++ new/labwc-0.20.2/po/te.po   2026-08-21 19:24:33.000000000 +0200
@@ -0,0 +1,80 @@
+# Labwc pot file
+# Copyright (C) 2024
+# This file is distributed under the same license as the labwc package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: labwc\n"
+"Report-Msgid-Bugs-To: https://github.com/labwc/labwc/issues\n";
+"POT-Creation-Date: 2024-09-19 21:09+1000\n"
+"PO-Revision-Date: 2026-07-16 08:01+0000\n"
+"Last-Translator: Gowtham Reddy Somala <[email protected]>\n"
+"Language-Team: Telugu <https://translate.lxqt-project.org/projects/labwc/";
+"labwc/te/>\n"
+"Language: te\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:1016
+msgid "Go there..."
+msgstr "అక్కడికి వెళ్ళు..."
+
+#: src/menu/menu.c:1034
+msgid "Terminal"
+msgstr "టెర్మినల్"
+
+#: src/menu/menu.c:1040
+msgid "Reconfigure"
+msgstr "పునర్వ్యవస్థీకరించు"
+
+#: src/menu/menu.c:1042
+msgid "Exit"
+msgstr "నిష్క్రమించు"
+
+#: src/menu/menu.c:1056
+msgid "Minimize"
+msgstr "కుదించండి"
+
+#: src/menu/menu.c:1058
+msgid "Maximize"
+msgstr "గరిష్ఠం చేయండి"
+
+#: src/menu/menu.c:1060
+msgid "Fullscreen"
+msgstr "పూర్తి స్క్రీన్"
+
+#: src/menu/menu.c:1062
+msgid "Roll Up/Down"
+msgstr "పైకి/కిందకు జరపండి"
+
+#: src/menu/menu.c:1064
+msgid "Decorations"
+msgstr "అలంకరణలు"
+
+#: src/menu/menu.c:1066
+msgid "Always on Top"
+msgstr "ఎల్లప్పుడూ పైన"
+
+#: src/menu/menu.c:1071
+msgid "Move Left"
+msgstr "ఎడమ వైపుకు"
+
+#: src/menu/menu.c:1078
+msgid "Move Right"
+msgstr "కుడి వైపుకు"
+
+#: src/menu/menu.c:1083
+msgid "Always on Visible Workspace"
+msgstr "ఎల్లప్పుడూ కనిపించే పని ప్రదేశం"
+
+#: src/menu/menu.c:1086
+msgid "Workspace"
+msgstr "పని ప్రదేశం"
+
+#: src/menu/menu.c:1089
+msgid "Close"
+msgstr "మూసివేయి"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/labwc-0.20.1/src/action.c 
new/labwc-0.20.2/src/action.c
--- old/labwc-0.20.1/src/action.c       2026-06-15 20:43:52.000000000 +0200
+++ new/labwc-0.20.2/src/action.c       2026-08-21 19:24:33.000000000 +0200
@@ -14,6 +14,7 @@
 #include "common/macros.h"
 #include "common/list.h"
 #include "common/mem.h"
+#include "common/nag.h"
 #include "common/parse-bool.h"
 #include "common/spawn.h"
 #include "common/string-helpers.h"
@@ -347,7 +348,7 @@
                        } else if (!strcasecmp(content, "current")) {
                                action_arg_add_int(action, argument, 
CYCLE_WORKSPACE_CURRENT);
                        } else {
-                               wlr_log(WLR_ERROR, "Invalid argument for action 
%s: '%s' (%s)",
+                               nag_log(WLR_ERROR, "Invalid argument for action 
%s: '%s' (%s)",
                                        action_names[action->type], argument, 
content);
                        }
                        goto cleanup;
@@ -360,7 +361,7 @@
                        } else if (!strcasecmp(content, "focused")) {
                                action_arg_add_int(action, argument, 
CYCLE_OUTPUT_FOCUSED);
                        } else {
-                               wlr_log(WLR_ERROR, "Invalid argument for action 
%s: '%s' (%s)",
+                               nag_log(WLR_ERROR, "Invalid argument for action 
%s: '%s' (%s)",
                                        action_names[action->type], argument, 
content);
                        }
                        goto cleanup;
@@ -371,7 +372,7 @@
                        } else if (!strcasecmp(content, "current")) {
                                action_arg_add_int(action, argument, 
CYCLE_APP_ID_CURRENT);
                        } else {
-                               wlr_log(WLR_ERROR, "Invalid argument for action 
%s: '%s' (%s)",
+                               nag_log(WLR_ERROR, "Invalid argument for action 
%s: '%s' (%s)",
                                        action_names[action->type], argument, 
content);
                        }
                        goto cleanup;
@@ -401,7 +402,7 @@
                if (!strcmp(argument, "direction")) {
                        enum view_axis axis = view_axis_parse(content);
                        if (axis == VIEW_AXIS_NONE || axis == 
VIEW_AXIS_INVALID) {
-                               wlr_log(WLR_ERROR, "Invalid argument for action 
%s: '%s' (%s)",
+                               nag_log(WLR_ERROR, "Invalid argument for action 
%s: '%s' (%s)",
                                        action_names[action->type], argument, 
content);
                        } else {
                                action_arg_add_int(action, argument, axis);
@@ -415,7 +416,7 @@
                        if (mode != LAB_SSD_MODE_INVALID) {
                                action_arg_add_int(action, argument, mode);
                        } else {
-                               wlr_log(WLR_ERROR, "Invalid argument for action 
%s: '%s' (%s)",
+                               nag_log(WLR_ERROR, "Invalid argument for action 
%s: '%s' (%s)",
                                        action_names[action->type], argument, 
content);
                        }
                        goto cleanup;
@@ -430,7 +431,7 @@
                        enum lab_edge edge = lab_edge_parse(content,
                                /*tiled*/ true, /*any*/ false);
                        if (edge == LAB_EDGE_NONE || edge == LAB_EDGE_CENTER) {
-                               wlr_log(WLR_ERROR,
+                               nag_log(WLR_ERROR,
                                        "Invalid argument for action %s: '%s' 
(%s)",
                                        action_names[action->type], argument, 
content);
                        } else {
@@ -497,7 +498,7 @@
                        enum lab_edge edge = lab_edge_parse(content,
                                /*tiled*/ false, /*any*/ false);
                        if (edge == LAB_EDGE_NONE) {
-                               wlr_log(WLR_ERROR, "Invalid argument for action 
%s: '%s' (%s)",
+                               nag_log(WLR_ERROR, "Invalid argument for action 
%s: '%s' (%s)",
                                        action_names[action->type], argument, 
content);
                        } else {
                                action_arg_add_int(action, argument, edge);
@@ -521,7 +522,7 @@
                        enum lab_placement_policy policy =
                                view_placement_parse(content);
                        if (policy == LAB_PLACE_INVALID) {
-                               wlr_log(WLR_ERROR, "Invalid argument for action 
%s: '%s' (%s)",
+                               nag_log(WLR_ERROR, "Invalid argument for action 
%s: '%s' (%s)",
                                                action_names[action->type], 
argument, content);
                        } else {
                                action_arg_add_int(action, argument, policy);
@@ -542,7 +543,7 @@
                goto cleanup;
        }
 
-       wlr_log(WLR_ERROR, "Invalid argument for action %s: '%s'",
+       nag_log(WLR_ERROR, "Invalid argument for action %s: '%s'",
                action_names[action->type], argument);
 
 cleanup:
@@ -557,7 +558,7 @@
                        return i;
                }
        }
-       wlr_log(WLR_ERROR, "Invalid action: %s", action_name);
+       nag_log(WLR_ERROR, "Invalid action: %s", action_name);
        return ACTION_TYPE_INVALID;
 }
 
@@ -565,7 +566,7 @@
 action_create(const char *action_name)
 {
        if (!action_name) {
-               wlr_log(WLR_ERROR, "action name not specified");
+               nag_log(WLR_ERROR, "action name not specified");
                return NULL;
        }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/labwc-0.20.1/src/common/buf.c 
new/labwc-0.20.2/src/common/buf.c
--- old/labwc-0.20.1/src/common/buf.c   2026-06-15 20:43:52.000000000 +0200
+++ new/labwc-0.20.2/src/common/buf.c   2026-08-21 19:24:33.000000000 +0200
@@ -15,7 +15,7 @@
 buf_expand_tilde(struct buf *s)
 {
        struct buf tmp = BUF_INIT;
-       for (int i = 0 ; i < s->len ; i++) {
+       for (int i = 0; i < s->len; i++) {
                if (s->data[i] == '~') {
                        buf_add(&tmp, getenv("HOME"));
                } else {
@@ -49,8 +49,8 @@
        struct buf tmp = BUF_INIT;
        struct buf environment_variable = BUF_INIT;
 
-       for (int i = 0 ; i < s->len ; i++) {
-               if (s->data[i] == '$' && isvalid(s->data[i+1])) {
+       for (int i = 0; i < s->len; i++) {
+               if (s->data[i] == '$' && isvalid(s->data[i + 1])) {
                        /* expand environment variable */
                        buf_clear(&environment_variable);
                        int len = 0;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/labwc-0.20.1/src/common/dir.c 
new/labwc-0.20.2/src/common/dir.c
--- old/labwc-0.20.1/src/common/dir.c   2026-06-15 20:43:52.000000000 +0200
+++ new/labwc-0.20.2/src/common/dir.c   2026-08-21 19:24:33.000000000 +0200
@@ -62,8 +62,15 @@
        struct wl_list *list;
 };
 
-struct wl_list *paths_get_prev(struct wl_list *elm) { return elm->prev; }
-struct wl_list *paths_get_next(struct wl_list *elm) { return elm->next; }
+struct wl_list *paths_get_prev(struct wl_list *elm)
+{
+       return elm->prev;
+}
+
+struct wl_list *paths_get_next(struct wl_list *elm)
+{
+       return elm->next;
+}
 
 static void
 build_config_path(struct ctx *ctx, char *prefix, const char *path)
@@ -117,9 +124,9 @@
                 * separated paths and that we have structured the
                 * .default_prefix in the same way.
                 */
-               gchar * *prefixes;
+               gchar **prefixes;
                prefixes = g_strsplit(prefix.data, ":", -1);
-               for (gchar * *p = prefixes; *p; p++) {
+               for (gchar **p = prefixes; *p; p++) {
                        ctx->build_path_fn(ctx, *p, d.path);
                        if (debug) {
                                fprintf(stderr, "%s\n", ctx->buf);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/labwc-0.20.1/src/common/meson.build 
new/labwc-0.20.2/src/common/meson.build
--- old/labwc-0.20.1/src/common/meson.build     2026-06-15 20:43:52.000000000 
+0200
+++ new/labwc-0.20.2/src/common/meson.build     2026-08-21 19:24:33.000000000 
+0200
@@ -10,6 +10,7 @@
   'lab-scene-rect.c',
   'match.c',
   'mem.c',
+  'nag.c',
   'nodename.c',
   'node-type.c',
   'parse-bool.c',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/labwc-0.20.1/src/common/nag.c 
new/labwc-0.20.2/src/common/nag.c
--- old/labwc-0.20.1/src/common/nag.c   1970-01-01 01:00:00.000000000 +0100
+++ new/labwc-0.20.2/src/common/nag.c   2026-08-21 19:24:33.000000000 +0200
@@ -0,0 +1,132 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#define _POSIX_C_SOURCE 200809L
+#include "common/nag.h"
+#include <assert.h>
+#include <unistd.h>
+#include <wlr/util/log.h>
+#include <wayland-server-core.h>
+#include "common/buf.h"
+#include "config/rcxml.h"
+#include "common/spawn.h"
+#include "labwc.h"
+
+static struct buf log_buf = BUF_INIT;
+static bool has_error = false;
+static pid_t pid = 0;
+static int pipe_w = -1;
+static struct wl_event_source *write_notifier = NULL;
+static size_t remaining = 0;
+
+struct buf *
+nag_get_buf(void)
+{
+       if (write_notifier) {
+               /*
+                * Ensure we are not accidentally modifying
+                * the buffer while writing it to a client.
+                *
+                * This may happend when using nag_log() after
+                * nag_show() without a nag_reset() in between.
+                */
+               wlr_log(WLR_ERROR, "Not writing to log buffer while sending to 
client");
+               return NULL;
+       }
+       return &log_buf;
+}
+
+void
+nag_set_error(enum wlr_log_importance importance)
+{
+       if (!has_error && importance == WLR_ERROR) {
+               has_error = true;
+       }
+}
+
+bool
+nag_check_pid(pid_t exited_pid)
+{
+       if (pid && pid == exited_pid) {
+               pid = 0;
+               return true;
+       }
+       return false;
+}
+
+void
+nag_reset(void)
+{
+       if (pid > 0) {
+               kill(pid, SIGTERM);
+               /* waitpid() is done in a generic SIGCHLD handler in 
src/server.c */
+               pid = 0;
+       }
+       if (write_notifier) {
+               wl_event_source_remove(write_notifier);
+               write_notifier = NULL;
+       }
+       if (pipe_w != -1) {
+               close(pipe_w);
+               pipe_w = -1;
+       }
+       has_error = false;
+       buf_clear(&log_buf);
+}
+
+static int
+handle_writable(int fd, uint32_t mask, void *data)
+{
+       assert(write_notifier);
+       assert(fd == pipe_w);
+       assert(remaining > 0);
+       assert(remaining <= (size_t)log_buf.len);
+
+       ssize_t bytes = write(fd, log_buf.data + (log_buf.len - remaining), 
remaining);
+       if (bytes < 0) {
+               wlr_log_errno(WLR_ERROR, "Failed to write errors to process 
%s", rc.error_command);
+       } else {
+               remaining -= bytes;
+               if (remaining > 0) {
+                       /* Keep waiting */
+                       return 0;
+               }
+       }
+
+       wl_event_source_remove(write_notifier);
+       write_notifier = NULL;
+
+       close(pipe_w);
+       pipe_w = -1;
+       return 0;
+}
+
+static void
+nag_show(void)
+{
+       if (!has_error || log_buf.len == 0) {
+               return;
+       }
+
+       pid = spawn_piped_async_no_shell(rc.error_command, &pipe_w);
+       if (pid < 0) {
+               wlr_log_errno(WLR_ERROR, "Failed to launch process: %s", 
rc.error_command);
+               return;
+       }
+
+       assert(!write_notifier);
+       remaining = log_buf.len;
+       write_notifier = wl_event_loop_add_fd(server.wl_event_loop,
+               pipe_w, WL_EVENT_WRITABLE, handle_writable, NULL);
+}
+
+void
+nag_show_callback(void *data)
+{
+       nag_show();
+}
+
+void
+nag_finish(void)
+{
+       nag_reset();
+       buf_reset(&log_buf);
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/labwc-0.20.1/src/common/spawn.c 
new/labwc-0.20.2/src/common/spawn.c
--- old/labwc-0.20.1/src/common/spawn.c 2026-06-15 20:43:52.000000000 +0200
+++ new/labwc-0.20.2/src/common/spawn.c 2026-08-21 19:24:33.000000000 +0200
@@ -30,13 +30,30 @@
        int flags = fcntl(fd, F_GETFD);
        if (flags == -1) {
                wlr_log_errno(WLR_ERROR,
-                       "Unable to set the CLOEXEC flag: fnctl failed");
+                       "Unable to get the CLOEXEC flag: fcntl failed");
                return false;
        }
        flags = flags | FD_CLOEXEC;
        if (fcntl(fd, F_SETFD, flags) == -1) {
                wlr_log_errno(WLR_ERROR,
-                       "Unable to set the CLOEXEC flag: fnctl failed");
+                       "Unable to set the CLOEXEC flag: fcntl failed");
+               return false;
+       }
+       return true;
+}
+
+static bool
+set_nonblock(int fd)
+{
+       int flags = fcntl(fd, F_GETFL);
+       if (flags == -1) {
+               wlr_log_errno(WLR_ERROR,
+                       "Unable to get the O_NONBLOCK flag: fcntl failed");
+               return false;
+       }
+       if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
+               wlr_log_errno(WLR_ERROR,
+                       "Unable to set the O_NONBLOCK flag: fcntl failed");
                return false;
        }
        return true;
@@ -156,6 +173,89 @@
 }
 
 pid_t
+spawn_piped_async_no_shell(const char *command, int *pipe_fd_w)
+{
+       assert(command);
+
+       GError *err = NULL;
+       gchar **argv = NULL;
+
+       /* Use glib's shell-parse to mimic Openbox's behaviour */
+       g_shell_parse_argv((gchar *)command, NULL, &argv, &err);
+       if (err) {
+               g_message("%s", err->message);
+               g_error_free(err);
+               return -1;
+       }
+
+       int pipe_rw[2];
+       if (pipe(pipe_rw) != 0) {
+               wlr_log(WLR_ERROR, "unable to pipe()");
+               g_strfreev(argv);
+               return -1;
+       }
+
+       pid_t child = 0;
+       child = fork();
+       if (child < 0) {
+               wlr_log(WLR_ERROR, "unable to fork() child");
+               close(pipe_rw[0]);
+               close(pipe_rw[1]);
+               g_strfreev(argv);
+               return child;
+       }
+
+       if (child == 0) {
+               /* Child */
+               reset_signals_and_limits();
+
+               /*
+                * replace stdout and stderr with /dev/null
+                * and stdin with the read end of the pipe
+                */
+               close(pipe_rw[1]);
+               dup2(pipe_rw[0], STDIN_FILENO);
+               close(pipe_rw[0]);
+
+               int dev_null = open("/dev/null", O_WRONLY);
+               if (dev_null < 0) {
+                       wlr_log_errno(WLR_ERROR, "opening /dev/null failed");
+                       /*
+                        * Just close stdout and stderr and
+                        * hope $command can deal with that.
+                        */
+                       close(STDOUT_FILENO);
+                       close(STDERR_FILENO);
+               } else {
+                       dup2(dev_null, STDOUT_FILENO);
+                       dup2(dev_null, STDERR_FILENO);
+                       close(dev_null);
+               }
+               execvp(argv[0], argv);
+               _exit(1);
+       }
+
+       /* labwc */
+       close(pipe_rw[0]);
+       g_strfreev(argv);
+
+       /*
+        * Prevent blocking of the labwc process when
+        * writing more than the pipe buffer can hold.
+        */
+       set_nonblock(pipe_rw[1]);
+
+       /*
+        * Prevent leaking the write end of the pipe to further
+        * children forked during the lifetime of the descriptor.
+        */
+       set_cloexec(pipe_rw[1]);
+       *pipe_fd_w = pipe_rw[1];
+
+       return child;
+}
+
+pid_t
 spawn_piped(const char *command, int *pipe_fd)
 {
        assert(command);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/labwc-0.20.1/src/common/string-helpers.c 
new/labwc-0.20.2/src/common/string-helpers.c
--- old/labwc-0.20.1/src/common/string-helpers.c        2026-06-15 
20:43:52.000000000 +0200
+++ new/labwc-0.20.2/src/common/string-helpers.c        2026-08-21 
19:24:33.000000000 +0200
@@ -57,6 +57,8 @@
 char *
 strdup_printf(const char *fmt, ...)
 {
+       assert(fmt);
+
        size_t size = 0;
        char *p = NULL;
        va_list ap;
@@ -84,7 +86,7 @@
 }
 
 char *
-str_join(const char *const parts[], const char *fmt, const char *sep)
+str_join(const char * const parts[], const char *fmt, const char *sep)
 {
        assert(parts);
 
@@ -102,7 +104,7 @@
        size_t sep_len = strlen(sep);
 
        /* Count the length of each formatted string */
-       for (const char *const *s = parts; *s; ++s) {
+       for (const char * const *s = parts; *s; ++s) {
                int n = snprintf(NULL, 0, fmt, *s);
                if (n < 0) {
                        return NULL;
@@ -121,7 +123,7 @@
        /* Concatenate the strings and separators */
        char *buf = xzalloc(size);
        char *p = buf;
-       for (const char *const *s = parts; *s; ++s) {
+       for (const char * const *s = parts; *s; ++s) {
                int n = 0;
 
                if (p != buf) {
@@ -152,7 +154,7 @@
 }
 
 static bool
-_str_endswith(const char *const string, const char *const suffix, uint32_t 
flags)
+_str_endswith(const char * const string, const char * const suffix, uint32_t 
flags)
 {
        size_t len_str = string ? strlen(string) : 0;
        size_t len_sfx = suffix ? strlen(suffix) : 0;
@@ -173,13 +175,13 @@
 }
 
 bool
-str_endswith(const char *const string, const char *const suffix)
+str_endswith(const char * const string, const char * const suffix)
 {
        return _str_endswith(string, suffix, STR_FLAG_NONE);
 }
 
 bool
-str_endswith_ignore_case(const char *const string, const char *const suffix)
+str_endswith_ignore_case(const char * const string, const char * const suffix)
 {
        return _str_endswith(string, suffix, STR_FLAG_IGNORE_CASE);
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/labwc-0.20.1/src/config/keybind.c 
new/labwc-0.20.2/src/config/keybind.c
--- old/labwc-0.20.1/src/config/keybind.c       2026-06-15 20:43:52.000000000 
+0200
+++ new/labwc-0.20.2/src/config/keybind.c       2026-08-21 19:24:33.000000000 
+0200
@@ -161,7 +161,7 @@
                         * "-". In order to avoid such duplications, we perform
                         * a lookahead on the tokens to treat that edge-case.
                         */
-                       if (symnames[i+1] && !symnames[i+1][0]) {
+                       if (symnames[i + 1] && !symnames[i + 1][0]) {
                                continue;
                        }
                        symname = "-";
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/labwc-0.20.1/src/config/rcxml.c 
new/labwc-0.20.2/src/config/rcxml.c
--- old/labwc-0.20.1/src/config/rcxml.c 2026-06-15 20:43:52.000000000 +0200
+++ new/labwc-0.20.2/src/config/rcxml.c 2026-08-21 19:24:33.000000000 +0200
@@ -17,6 +17,7 @@
 #include "common/list.h"
 #include "common/macros.h"
 #include "common/mem.h"
+#include "common/nag.h"
 #include "common/nodename.h"
 #include "common/parse-bool.h"
 #include "common/parse-double.h"
@@ -1167,6 +1168,8 @@
 
        } else if (!strcasecmp(nodename, "promptCommand.core")) {
                xstrdup_replace(rc.prompt_command, content);
+       } else if (!strcasecmp(nodename, "errorCommand.core")) {
+               xstrdup_replace(rc.error_command, content);
 
        } else if (!strcmp(nodename, "policy.placement")) {
                enum lab_placement_policy policy = 
view_placement_parse(content);
@@ -1476,7 +1479,7 @@
        int options = 0;
        xmlDoc *d = xmlReadMemory(b->data, b->len, NULL, NULL, options);
        if (!d) {
-               wlr_log(WLR_ERROR, "error parsing config file");
+               nag_log(WLR_ERROR, "error parsing config file");
                return;
        }
        xmlNode *root = xmlDocGetRootElement(d);
@@ -1802,6 +1805,15 @@
                                "--layer overlay "
                                "--timeout 0");
        }
+       if (!rc.error_command) {
+               rc.error_command =
+                       xstrdup("labnag "
+                               "--message 'Config errors detected' "
+                               "--button-dismiss 'Close' "
+                               "--layer overlay "
+                               "--timeout 0 "
+                               "--detailed-message");
+       }
        if (!rc.fallback_app_icon_name) {
                rc.fallback_app_icon_name = xstrdup("labwc");
        }
@@ -2030,7 +2042,7 @@
                        continue;
                }
 
-               wlr_log(WLR_INFO, "read config file %s", path->string);
+               nag_log(WLR_INFO, "read config file %s", path->string);
 
                rcxml_parse_xml(&b);
                buf_reset(&b);
@@ -2052,6 +2064,7 @@
        zfree(rc.font_menuitem.name);
        zfree(rc.font_osd.name);
        zfree(rc.prompt_command);
+       zfree(rc.error_command);
        zfree(rc.theme_name);
        zfree(rc.icon_theme_name);
        zfree(rc.fallback_app_icon_name);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/labwc-0.20.1/src/config/session.c 
new/labwc-0.20.2/src/config/session.c
--- old/labwc-0.20.1/src/config/session.c       2026-06-15 20:43:52.000000000 
+0200
+++ new/labwc-0.20.2/src/config/session.c       2026-08-21 19:24:33.000000000 
+0200
@@ -26,7 +26,7 @@
        #define wlr_backend_is_drm(backend) (false)
 #endif
 
-static const char *const env_vars[] = {
+static const char * const env_vars[] = {
        "WAYLAND_DISPLAY",
        "XDG_CURRENT_DESKTOP",
        "XCURSOR_SIZE",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/labwc-0.20.1/src/cycle/cycle.c 
new/labwc-0.20.2/src/cycle/cycle.c
--- old/labwc-0.20.1/src/cycle/cycle.c  2026-06-15 20:43:52.000000000 +0200
+++ new/labwc-0.20.2/src/cycle/cycle.c  2026-08-21 19:24:33.000000000 +0200
@@ -204,7 +204,7 @@
        struct view *selected_view = server.cycle.selected_view;
        destroy_cycle();
 
-       seat_focus_override_end(&server.seat, /*restore_focus*/ false);
+       seat_focus_override_end(&server.seat, /*restore_focus*/ !switch_focus);
 
        /* Hiding OSD may need a cursor change */
        cursor_update_focus();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/labwc-0.20.1/src/img/img.c 
new/labwc-0.20.2/src/img/img.c
--- old/labwc-0.20.1/src/img/img.c      2026-06-15 20:43:52.000000000 +0200
+++ new/labwc-0.20.2/src/img/img.c      2026-08-21 19:24:33.000000000 +0200
@@ -105,7 +105,7 @@
 }
 
 void
-lab_img_add_modifier(struct lab_img *img,  lab_img_modifier_func_t modifier)
+lab_img_add_modifier(struct lab_img *img, lab_img_modifier_func_t modifier)
 {
        lab_img_modifier_func_t *mod = wl_array_add(&img->modifiers, 
sizeof(*mod));
        *mod = modifier;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/labwc-0.20.1/src/input/tablet.c 
new/labwc-0.20.2/src/input/tablet.c
--- old/labwc-0.20.1/src/input/tablet.c 2026-06-15 20:43:52.000000000 +0200
+++ new/labwc-0.20.2/src/input/tablet.c 2026-08-21 19:24:33.000000000 +0200
@@ -199,7 +199,7 @@
        *dy = *dy * motion_sensitivity;
 }
 
-static struct wlr_surface*
+static struct wlr_surface *
 tablet_get_coords(struct drawing_tablet *tablet, struct drawing_tablet_tool 
*tool,
                double *x, double *y, double *dx, double *dy)
 {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/labwc-0.20.1/src/input/touch.c 
new/labwc-0.20.2/src/input/touch.c
--- old/labwc-0.20.1/src/input/touch.c  2026-06-15 20:43:52.000000000 +0200
+++ new/labwc-0.20.2/src/input/touch.c  2026-08-21 19:24:33.000000000 +0200
@@ -27,7 +27,7 @@
        struct wl_list link; /* seat.touch_points */
 };
 
-static struct wlr_surface*
+static struct wlr_surface *
 touch_get_coords(struct seat *seat, struct wlr_touch *touch, double x, double 
y,
                double *x_offset, double *y_offset)
 {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/labwc-0.20.1/src/interactive.c 
new/labwc-0.20.2/src/interactive.c
--- old/labwc-0.20.1/src/interactive.c  2026-06-15 20:43:52.000000000 +0200
+++ new/labwc-0.20.2/src/interactive.c  2026-08-21 19:24:33.000000000 +0200
@@ -267,7 +267,7 @@
                } else if (right < rc.snap_edge_corner_range) {
                        *edge2 = LAB_EDGE_RIGHT;
                }
-       } else if (*edge1  == LAB_EDGE_LEFT || *edge1 == LAB_EDGE_RIGHT) {
+       } else if (*edge1 == LAB_EDGE_LEFT || *edge1 == LAB_EDGE_RIGHT) {
                if (top < rc.snap_edge_corner_range) {
                        *edge2 = LAB_EDGE_TOP;
                } else if (bottom < rc.snap_edge_corner_range) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/labwc-0.20.1/src/output.c 
new/labwc-0.20.2/src/output.c
--- old/labwc-0.20.1/src/output.c       2026-06-15 20:43:52.000000000 +0200
+++ new/labwc-0.20.2/src/output.c       2026-08-21 19:24:33.000000000 +0200
@@ -85,7 +85,8 @@
 };
 
 static bool
-output_set_render_format(struct output *output, uint32_t candidates[], size_t 
count)
+output_set_render_format(struct output *output, uint32_t candidates[],
+               size_t count, bool silent)
 {
        for (size_t i = 0; i < count; i++) {
                wlr_output_state_set_render_format(&output->pending, 
candidates[i]);
@@ -93,6 +94,16 @@
                        return true;
                }
        }
+       if (!silent) {
+               wlr_log(WLR_DEBUG, "output %s supports none of the %zu 
candidate"
+                       " render formats", output->wlr_output->name, count);
+       }
+       /*
+        * Leaving the last candidate tried on the pending state means no
+        * swapchain can be created for this output at all, so clear the flag
+        * and leave the format alone instead.
+        */
+       output->pending.committed &= ~WLR_OUTPUT_STATE_RENDER_FORMAT;
        return false;
 }
 
@@ -174,14 +185,14 @@
                hdr_succeeded = true;
        } else if (render_bit_depth == LAB_RENDER_BIT_DEPTH_10) {
                hdr_succeeded = output_set_render_format(output, 
output_formats_10bit,
-                       ARRAY_SIZE(output_formats_10bit));
+                       ARRAY_SIZE(output_formats_10bit), silent);
                if (!hdr_succeeded) {
                        if (!silent) {
                                wlr_log(WLR_INFO, "No 10 bit color formats"
                                        " supported, HDR disabled.");
                        }
                        if (!output_set_render_format(output, 
output_formats_8bit,
-                                       ARRAY_SIZE(output_formats_8bit))) {
+                                       ARRAY_SIZE(output_formats_8bit), 
silent)) {
                                if (!silent) {
                                        wlr_log(WLR_ERROR, "No 8 bit color 
formats"
                                                " supported either!");
@@ -190,7 +201,7 @@
                }
        } else {
                if (!output_set_render_format(output, output_formats_8bit,
-                               ARRAY_SIZE(output_formats_8bit)) && !silent) {
+                               ARRAY_SIZE(output_formats_8bit), silent) && 
!silent) {
                        wlr_log(WLR_ERROR, "No 8 bit color formats supported!");
                }
        }
@@ -280,6 +291,21 @@
        if (seat->overlay.active.output == output) {
                overlay_finish(seat);
        }
+
+       /*
+        * Destroy the scene output before changing the scene graph below.
+        * Otherwise those changes can send a surface-enter for this output 
while
+        * its destroy signal is already being emitted. The new listener then
+        * misses that signal and makes wlr_output_finish() abort because
+        * output->events.bind is not empty.
+        *
+        * See https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/4096
+        */
+       if (output->scene_output) {
+               wlr_scene_output_destroy(output->scene_output);
+               output->scene_output = NULL;
+       }
+
        wl_list_remove(&output->link);
        wl_list_remove(&output->frame.link);
        wl_list_remove(&output->destroy.link);
@@ -327,10 +353,6 @@
                wl_display_terminate(server.wl_display);
        }
 
-       /*
-        * output->scene_output (if still around at this point) is
-        * destroyed automatically when the wlr_output is destroyed
-        */
        free(output);
 }
 
@@ -394,9 +416,9 @@
                        return;
                }
                /*
-                * Note: wlr_scene_output_layout_add_output() is not
-                * safe to call twice, so we call it only when initially
-                * creating the scene_output.
+                * Note: wlr_scene_output_layout_add_output() is safe to
+                * call multiple times, but we only need to add the output
+                * when initially creating the scene_output.
                 */
                wlr_scene_output_layout_add_output(server.scene_layout,
                        layout_output, output->scene_output);
@@ -530,6 +552,30 @@
        server.pending_output_layout_change--;
 
        /*
+        * Force the initial modeset commit to actually happen.
+        *
+        * lab_wlr_scene_output_commit() skips the real commit whenever the
+        * scene reports neither damage nor needs_frame. But on this very
+        * first commit the output has not been modeset yet, so its resolution
+        * is still 0x0: scene damage is clipped against that empty area and
+        * can never accumulate, and needs_frame is never raised on its own.
+        * As a result the enabled=true state set above would never be
+        * committed and the output would stay black until some unrelated
+        * event (VT switch, hotplug, display-manager restart) happens to
+        * raise needs_frame.
+        *
+        * With hardware cursors this is masked, because uploading the cursor
+        * image raises needs_frame as a side effect. With
+        * WLR_NO_HARDWARE_CURSORS=1 (software cursors) that path is gone and
+        * the missing initial commit becomes reliably reproducible, e.g.
+        * under QEMU/virtio-gpu.
+        *
+        * Schedule a frame here so needs_frame is raised and this enable is
+        * always committed, independent of the cursor mode.
+        */
+       wlr_output_schedule_frame(wlr_output);
+
+       /*
         * Commit the output this way instead, HDR needs a buffer, and
         * this commit must be called after the output is added to the
         * layout above.
@@ -869,12 +915,9 @@
                                server.workspaces.ext_group, 
output->wlr_output);
 
                        /*
-                        * At time of writing, wlr_output_layout_remove()
-                        * indirectly destroys the wlr_scene_output, but
-                        * this behavior may change in future. To remove
-                        * doubt and avoid either a leak or double-free,
-                        * explicitly destroy the wlr_scene_output before
-                        * calling wlr_output_layout_remove().
+                        * wlr_output_layout_remove() only unbinds the
+                        * wlr_scene_output from the layout; it does not
+                        * destroy it. Destroy explicitly to avoid a leak.
                         */
                        wlr_scene_output_destroy(output->scene_output);
                        wlr_output_layout_remove(server.output_layout, o);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/labwc-0.20.1/src/server.c 
new/labwc-0.20.2/src/server.c
--- old/labwc-0.20.1/src/server.c       2026-06-15 20:43:52.000000000 +0200
+++ new/labwc-0.20.2/src/server.c       2026-08-21 19:24:33.000000000 +0200
@@ -54,6 +54,7 @@
 #include "action.h"
 #include "common/macros.h"
 #include "common/mem.h"
+#include "common/nag.h"
 #include "common/scene-helpers.h"
 #include "config/rcxml.h"
 #include "config/session.h"
@@ -98,6 +99,7 @@
 
        scaled_buffer_invalidate_sharing();
        rcxml_finish();
+       nag_reset();
        rcxml_read(rc.config_file);
        theme_finish(rc.theme);
        theme_init(rc.theme, rc.theme_name);
@@ -119,6 +121,8 @@
        resize_indicator_reconfigure();
        kde_server_decoration_update_default();
        workspaces_reconfigure();
+
+       wl_event_loop_add_idle(server.wl_event_loop, nag_show_callback, NULL);
 }
 
 static int
@@ -146,62 +150,90 @@
        siginfo_t info;
        info.si_pid = 0;
 
-       /* First call waitid() with NOWAIT which doesn't consume the zombie */
-       if (waitid(P_ALL, /*id*/ 0, &info, WEXITED | WNOHANG | WNOWAIT) == -1) {
-               return 0;
-       }
+       /*
+        * We may get a single SIGCHILD event although there are
+        * multiple childs terminating so we loop through them.
+        *
+        * A 'while true; labwc --reconfigure; done' loop along
+        * with some config error which causes labnag to re-spawn
+        * constantly is a good test for this handler.
+        */
 
-       if (info.si_pid == 0) {
-               /* No children in waitable state */
-               return 0;
-       }
+       /* First call waitid() with NOWAIT which doesn't consume the zombie. */
+       while (waitid(P_ALL, /*id*/ 0, &info, WEXITED | WNOHANG | WNOWAIT) != 
-1) {
+               if (info.si_pid == 0) {
+                       /* No children in waitable state */
+                       return 0;
+               }
 
-#if HAVE_XWAYLAND
-       /* Ensure that we do not break xwayland lazy initialization */
-       if (server.xwayland && server.xwayland->server
-                       && info.si_pid == server.xwayland->server->pid) {
-               return 0;
-       }
-#endif
+       #if HAVE_XWAYLAND
+               /* Ensure that we do not break xwayland lazy initialization */
+               if (server.xwayland && server.xwayland->server
+                               && info.si_pid == server.xwayland->server->pid) 
{
+                       /*
+                        * We need to completely return here to prevent running
+                        * into an endless loop without giving the wlroots 
internal
+                        * xwayland startup handler a chance to use its own 
waitid().
+                        *
+                        * Further queued up child process terminatations will 
be
+                        * dealt with on the next SIGCHLD handler invocation and
+                        * float around as zombies until that point.
+                        */
+                       return 0;
+               }
+       #endif
 
-       /* And then do the actual (consuming) lookup again */
-       int ret = waitid(P_PID, info.si_pid, &info, WEXITED);
-       if (ret == -1) {
-               wlr_log(WLR_ERROR, "blocking waitid() for %ld failed: %d",
-                       (long)info.si_pid, ret);
-               return 0;
-       }
+               /* And then do the actual (consuming) lookup again */
+               int ret = waitid(P_PID, info.si_pid, &info, WEXITED);
+               if (ret == -1) {
+                       wlr_log(WLR_ERROR, "blocking waitid() for %ld failed: 
%d",
+                               (long)info.si_pid, ret);
+                       goto check_next;
+               }
 
-       const char *signame;
-       switch (info.si_code) {
-       case CLD_EXITED:
-               if (!action_check_prompt_result(info.si_pid, info.si_status)) {
-                       wlr_log(info.si_status == 0 ? WLR_DEBUG : WLR_ERROR,
-                               "spawned child %ld exited with %d",
-                               (long)info.si_pid, info.si_status);
+               const char *signame;
+               switch (info.si_code) {
+               case CLD_EXITED:
+                       if (!action_check_prompt_result(info.si_pid, 
info.si_status)
+                                       && !nag_check_pid(info.si_pid)) {
+                               wlr_log(info.si_status == 0 ? WLR_DEBUG : 
WLR_ERROR,
+                                       "spawned child %ld exited with %d",
+                                       (long)info.si_pid, info.si_status);
+                       }
+                       break;
+               case CLD_KILLED:
+               case CLD_DUMPED:
+                       signame = strsignal(info.si_status);
+                       wlr_log(WLR_ERROR,
+                               "spawned child %ld terminated with signal %d 
(%s)",
+                                       (long)info.si_pid, info.si_status,
+                                       signame ? signame : "unknown");
+                       /* Allow cleanup of killed prompt */
+                       action_check_prompt_result(info.si_pid, 
-info.si_status);
+                       nag_check_pid(info.si_pid);
+                       break;
+               default:
+                       wlr_log(WLR_ERROR,
+                               "spawned child %ld terminated unexpectedly: %d"
+                               " please report", (long)info.si_pid, 
info.si_code);
                }
-               break;
-       case CLD_KILLED:
-       case CLD_DUMPED:
-               signame = strsignal(info.si_status);
-               wlr_log(WLR_ERROR,
-                       "spawned child %ld terminated with signal %d (%s)",
-                               (long)info.si_pid, info.si_status,
-                               signame ? signame : "unknown");
-               /* Allow cleanup of killed prompt */
-               action_check_prompt_result(info.si_pid, -info.si_status);
-               break;
-       default:
-               wlr_log(WLR_ERROR,
-                       "spawned child %ld terminated unexpectedly: %d"
-                       " please report", (long)info.si_pid, info.si_code);
-       }
-
-       if (info.si_pid == server.primary_client_pid) {
-               wlr_log(WLR_INFO, "primary client %ld exited", 
(long)info.si_pid);
-               wl_display_terminate(server.wl_display);
-       }
 
+               if (info.si_pid == server.primary_client_pid) {
+                       wlr_log(WLR_INFO, "primary client %ld exited", 
(long)info.si_pid);
+                       wl_display_terminate(server.wl_display);
+               }
+check_next:
+               /*
+                * We need each initial WNOHANG | WNOWAIT call to clearly 
identify
+                * if there are no more children to wait for so we reset si_pid
+                * as recommended for portability in the waitid man page.
+                *
+                * Note that at least on one of the devs linux system the call
+                * actually returns with -1 in that case, contrary to what is
+                * written in the man page. We do handle both cases.
+                */
+               info.si_pid = 0;
+       }
        return 0;
 }
 
@@ -809,6 +841,7 @@
 #if HAVE_XWAYLAND
        xwayland_server_init(server.compositor);
 #endif
+       wl_event_loop_add_idle(server.wl_event_loop, nag_show_callback, NULL);
 }
 
 void
@@ -856,6 +889,7 @@
 
        wl_display_destroy_clients(server.wl_display);
 
+       nag_finish();
        seat_finish();
        output_finish();
        xdg_shell_finish();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/labwc-0.20.1/src/workspaces.c 
new/labwc-0.20.2/src/workspaces.c
--- old/labwc-0.20.1/src/workspaces.c   2026-06-15 20:43:52.000000000 +0200
+++ new/labwc-0.20.2/src/workspaces.c   2026-08-21 19:24:33.000000000 +0200
@@ -115,7 +115,7 @@
                if (!hide_boxes) {
                        x = (width - marker_width) / 2;
                        wl_list_for_each(workspace, &server.workspaces.all, 
link) {
-                               bool active =  workspace == 
server.workspaces.current;
+                               bool active = workspace == 
server.workspaces.current;
                                set_cairo_color(cairo, 
rc.theme->osd_label_text_color);
                                struct wlr_fbox fbox = {
                                        .x = x,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/labwc-0.20.1/src/xwayland.c 
new/labwc-0.20.2/src/xwayland.c
--- old/labwc-0.20.1/src/xwayland.c     2026-06-15 20:43:52.000000000 +0200
+++ new/labwc-0.20.2/src/xwayland.c     2026-08-21 19:24:33.000000000 +0200
@@ -590,15 +590,13 @@
        struct view *view = &xwayland_view->base;
 
        /*
-        * Use the WM_CLASS 'instance' (1st string) for the app_id. Per
-        * ICCCM, this is usually "the trailing part of the name used to
-        * invoke the program (argv[0] stripped of any directory names)".
-        *
-        * In most cases, the 'class' (2nd string) is the same as the
-        * 'instance' except for being capitalized. We want lowercase
-        * here since we use the app_id for icon lookups.
+        * Use the WM_CLASS 'class' (2nd string) for the app_id. (Note
+        * that this is often capitalized, which must be accounted for
+        * in icon lookups.) We used to use the 'instance' (1st string)
+        * but this caused missing icons with Firefox, which has an
+        * instance of 'Navigator' for historical reasons.
         */
-       view_set_app_id(view, xwayland_view->xwayland_surface->instance);
+       view_set_app_id(view, xwayland_view->xwayland_surface->class);
 }
 
 static void

Reply via email to