Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package foot for openSUSE:Factory checked in 
at 2024-08-16 12:23:32
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/foot (Old)
 and      /work/SRC/openSUSE:Factory/.foot.new.2698 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "foot"

Fri Aug 16 12:23:32 2024 rev:35 rq:1194032 version:1.18.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/foot/foot.changes        2024-08-03 
20:05:05.420414787 +0200
+++ /work/SRC/openSUSE:Factory/.foot.new.2698/foot.changes      2024-08-16 
12:24:03.040031251 +0200
@@ -1,0 +2,14 @@
+Wed Aug 14 16:27:10 UTC 2024 - Arnav Singh <opens...@arnavion.dev>
+
+- Update to v1.18.1:
+  * foot.ini options:
+    * desktop-notifications.command config can now also use "${muted}"
+      and "${sound-name}" in its template value.
+  * CSD buttons now activate on mouse button release, rather than press.
+  * Desktop notifications via OSC-99 sequence can now choose to play
+    a particular sound or mute the sound.
+  * Fixed bug in OSC-111 sequence used to reset background color not handling
+    alpha changes correctly, causing visual glitches.
+  * See https://codeberg.org/dnkl/foot/releases/tag/1.18.1 for more details.
+
+-------------------------------------------------------------------

Old:
----
  foot-1.18.0.tar.gz
  foot-1.18.0.tar.gz.sig

New:
----
  foot-1.18.1.tar.gz
  foot-1.18.1.tar.gz.sig

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

Other differences:
------------------
++++++ foot.spec ++++++
--- /var/tmp/diff_new_pack.jOeSi3/_old  2024-08-16 12:24:03.676057684 +0200
+++ /var/tmp/diff_new_pack.jOeSi3/_new  2024-08-16 12:24:03.680057850 +0200
@@ -20,7 +20,7 @@
 %define _distconfdir %{_sysconfdir}
 %endif
 Name:           foot
-Version:        1.18.0
+Version:        1.18.1
 Release:        0
 Summary:        A Wayland terminal emulator
 License:        MIT

++++++ foot-1.18.0.tar.gz -> foot-1.18.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/foot-1.18.0/CHANGELOG.md new/foot-1.18.1/CHANGELOG.md
--- old/foot-1.18.0/CHANGELOG.md        2024-08-02 14:28:16.000000000 +0200
+++ new/foot-1.18.1/CHANGELOG.md        2024-08-14 12:00:20.000000000 +0200
@@ -1,5 +1,6 @@
 # Changelog
 
+* [1.18.1](#1-18-1)
 * [1.18.0](#1-18-0)
 * [1.17.2](#1-17-2)
 * [1.17.1](#1-17-1)
@@ -52,6 +53,37 @@
 * [1.2.0](#1-2-0)
 
 
+## 1.18.1
+
+### Added
+
+* OSC-99: support for the `s` parameter. Supported keywords are
+  `silent`, `system` and names from the freedesktop sound naming
+  specification.
+* `${muted}` and `${sound-name}` added to the
+  `desktop-notifications.command` template.
+
+
+### Changed
+
+* CSD buttons now activate on mouse button **release**, rather than
+  press ([#1787][1787]).
+
+
+### Fixed
+
+* Regression: OSC-111 not handling alpha changes correctly, causing
+  visual glitches ([#1801][1801]).
+
+[1801]: https://codeberg.org/dnkl/foot/issues/1801
+
+
+### Contributors
+
+* Craig Barnes
+* Shogo Yamazaki
+
+
 ## 1.18.0
 
 ### Added
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/foot-1.18.0/README.md new/foot-1.18.1/README.md
--- old/foot-1.18.0/README.md   2024-08-02 14:28:16.000000000 +0200
+++ new/foot-1.18.1/README.md   2024-08-14 12:00:20.000000000 +0200
@@ -3,10 +3,8 @@
 The fast, lightweight and minimalistic Wayland terminal emulator.
 
 [![CI 
status](https://ci.codeberg.org/api/badges/dnkl/foot/status.svg)](https://ci.codeberg.org/dnkl/foot)
-[![Pipeline 
status](https://gitlab.com/dnkl/foot/badges/master/pipeline.svg)](https://gitlab.com/dnkl/foot/commits/master)
-[![builds.sr.ht 
status](https://builds.sr.ht/~dnkl/foot.svg)](https://builds.sr.ht/~dnkl/foot?)
 
-[![Packaging 
status](https://repology.org/badge/vertical-allrepos/foot.svg)](https://repology.org/project/foot/versions)
+[![Packaging 
status](https://repology.org/badge/vertical-allrepos/foot.svg?columns=4)](https://repology.org/project/foot/versions)
 
 
 ## Index
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/foot-1.18.0/config.c new/foot-1.18.1/config.c
--- old/foot-1.18.0/config.c    2024-08-02 14:28:16.000000000 +0200
+++ new/foot-1.18.1/config.c    2024-08-14 12:00:20.000000000 +0200
@@ -356,9 +356,9 @@
 
     /* First, check XDG_CONFIG_HOME (or .config, if unset) */
     if (xdg_config_home != NULL && xdg_config_home[0] != '\0')
-        path = xstrjoin(xdg_config_home, "/foot/foot.ini", 0);
+        path = xstrjoin(xdg_config_home, "/foot/foot.ini");
     else if (home_dir != NULL)
-        path = xstrjoin(home_dir, "/.config/foot/foot.ini", 0);
+        path = xstrjoin(home_dir, "/.config/foot/foot.ini");
 
     if (path != NULL) {
         LOG_DBG("checking for %s", path);
@@ -383,7 +383,7 @@
          conf_dir = strtok(NULL, ":"))
     {
         free(path);
-        path = xstrjoin(conf_dir, "/foot/foot.ini", 0);
+        path = xstrjoin(conf_dir, "/foot/foot.ini");
 
         LOG_DBG("checking for %s", path);
         int fd = open(path, O_RDONLY | O_CLOEXEC);
@@ -843,7 +843,7 @@
                 return false;
             }
 
-            _include_path = xasprintf("%s/%s", home_dir, value + 2);
+            _include_path = xstrjoin3(home_dir, "/", value + 2);
             include_path = _include_path;
         } else
             include_path = value;
@@ -2931,7 +2931,7 @@
 
     const char *wayland_display = getenv("WAYLAND_DISPLAY");
     if (wayland_display == NULL) {
-        return xstrjoin(xdg_runtime, "/foot.sock", 0);
+        return xstrjoin(xdg_runtime, "/foot.sock");
     }
 
     return xasprintf("%s/foot-%s.sock", xdg_runtime, wayland_display);
@@ -3242,7 +3242,7 @@
     parse_modifiers(XKB_MOD_NAME_SHIFT, 5, 
&conf->mouse.selection_override_modifiers);
 
     tokenize_cmdline(
-        "notify-send --wait --app-name ${app-id} --icon ${app-id} --category 
${category} --urgency ${urgency} --expire-time ${expire-time} --hint 
STRING:image-path:${icon} --replace-id ${replace-id} ${action-argument} 
--print-id -- ${title} ${body}",
+        "notify-send --wait --app-name ${app-id} --icon ${app-id} --category 
${category} --urgency ${urgency} --expire-time ${expire-time} --hint 
STRING:image-path:${icon} --hint BOOLEAN:suppress-sound:${muted} --hint 
STRING:sound-name:${sound-name} --replace-id ${replace-id} ${action-argument} 
--print-id -- ${title} ${body}",
         &conf->desktop_notifications.command.argv.args);
     tokenize_cmdline("--action ${action-name}=${action-label}", 
&conf->desktop_notifications.command_action_arg.argv.args);
     tokenize_cmdline("xdg-open ${url}", &conf->url.launch.argv.args);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/foot-1.18.0/doc/foot.ini.5.scd 
new/foot-1.18.1/doc/foot.ini.5.scd
--- old/foot-1.18.0/doc/foot.ini.5.scd  2024-08-02 14:28:16.000000000 +0200
+++ new/foot-1.18.1/doc/foot.ini.5.scd  2024-08-14 12:00:20.000000000 +0200
@@ -179,9 +179,10 @@
 
        Default: _unset_
 
-*box-drawings-uses-font-glyphs* Boolean. When disabled, foot generates
-       box/line drawing characters itself. The are several advantages to
-       doing this instead of using font glyphs:
+*box-drawings-uses-font-glyphs*
+       Boolean. When disabled, foot generates box/line drawing characters
+       itself. The are several advantages to doing this instead of using
+       font glyphs:
        
                - No antialiasing effects where e.g. line endpoints appear
                  dimmed down, or blurred.
@@ -195,6 +196,13 @@
        When enabled, box/line drawing characters are rendered using font
        glyphs. This may result in a more uniform look, in some use cases.
        
+       When disabled, foot will render the following Unicode codepoints
+       by itself:
+       
+               - U+02500 - U+0259F
+               - U+02800 - U+028FF
+               - U+1Fb00 - U+1FB9B
+       
        Default: _no_.
 
 *dpi-aware*
@@ -459,6 +467,17 @@
                below. Can be used together with e.g. notify-send's
                *--replace-id* option.
                
+               _${muted}_ is replaced by either *true* or *false*, depending
+               on whether the notification has requested all notification
+               sounds be muted. It is intended to set the *suppress-sound*
+               hint (with e.g. notify-send's *--hint* option).
+               
+               _${sound-name}_ is replaced by sound-name requested by the
+               notification. This should be a name from the freedesktop sound
+               naming specification, but this is not something that foot
+               enforces. It is intended to set the *sound-name* hint (with
+               e.g. notify-send's *--hint* option).
+               
                _${action-argument}_ will be expanded to the
                *command-action-argument* option, for each notification
                action. There will always be at least one action, the
@@ -568,6 +587,8 @@
                        --urgency     ${urgency}++
                        --expire-time ${expire-time}++
                        --hint        STRING:image-path:${icon}++
+                       --hint        BOOLEAN:suppress-sound:${muted}++
+                       --hint        STRING:sound-name:${sound-name}++
                        --replace-id  ${replace-id}++
                        ${action-argument}++
                        --print-id++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/foot-1.18.0/foot.ini new/foot-1.18.1/foot.ini
--- old/foot-1.18.0/foot.ini    2024-08-02 14:28:16.000000000 +0200
+++ new/foot-1.18.1/foot.ini    2024-08-14 12:00:20.000000000 +0200
@@ -47,7 +47,7 @@
 # command-focused=no
 
 [desktop-notifications]
-# command=notify-send --wait --app-name ${app-id} --icon ${app-id} --category 
${category} --urgency ${urgency} --expire-time ${expire-time} --hint 
STRING:image-path:${icon} --replace-id ${replace-id} ${action-argument} 
--print-id -- ${title} ${body}
+# command=notify-send --wait --app-name ${app-id} --icon ${app-id} --category 
${category} --urgency ${urgency} --expire-time ${expire-time} --hint 
STRING:image-path:${icon} --hint BOOLEAN:suppress-sound:${muted} --hint 
STRING:sound-name:${sound-name} --replace-id ${replace-id} ${action-argument} 
--print-id -- ${title} ${body}
 # command-action-argument=--action ${action-name}=${action-label}
 # close=""
 # inhibit-when-focused=yes
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/foot-1.18.0/input.c new/foot-1.18.1/input.c
--- old/foot-1.18.0/input.c     2024-08-02 14:28:16.000000000 +0200
+++ new/foot-1.18.1/input.c     2024-08-14 12:00:20.000000000 +0200
@@ -2053,6 +2053,25 @@
     }
 }
 
+static bool
+pointer_is_on_button(const struct terminal *term, const struct seat *seat,
+                     enum csd_surface csd_surface)
+{
+    if (seat->mouse.x < 0)
+        return false;
+    if (seat->mouse.y < 0)
+        return false;
+
+    struct csd_data info = get_csd_data(term, csd_surface);
+    if (seat->mouse.x > info.width)
+        return false;
+
+    if (seat->mouse.y > info.height)
+        return false;
+
+    return true;
+}
+
 static void
 wl_pointer_motion(void *data, struct wl_pointer *wl_pointer,
                   uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y)
@@ -2085,16 +2104,42 @@
     int x = wl_fixed_to_int(surface_x) * term->scale;
     int y = wl_fixed_to_int(surface_y) * term->scale;
 
+    enum term_surface surf_kind = term->active_surface;
+    int button = 0;
+    bool send_to_client = false;
+    bool is_on_button = false;
+
+    /* If current surface is a button, check if pointer was on it
+       *before* the motion event */
+    switch (surf_kind) {
+    case TERM_SURF_BUTTON_MINIMIZE:
+        is_on_button = pointer_is_on_button(term, seat, CSD_SURF_MINIMIZE);
+        break;
+
+    case TERM_SURF_BUTTON_MAXIMIZE:
+        is_on_button = pointer_is_on_button(term, seat, CSD_SURF_MAXIMIZE);
+        break;
+
+    case TERM_SURF_BUTTON_CLOSE:
+        is_on_button = pointer_is_on_button(term, seat, CSD_SURF_CLOSE);
+        break;
+
+    case TERM_SURF_NONE:
+    case TERM_SURF_GRID:
+    case TERM_SURF_TITLE:
+    case TERM_SURF_BORDER_LEFT:
+    case TERM_SURF_BORDER_RIGHT:
+    case TERM_SURF_BORDER_TOP:
+    case TERM_SURF_BORDER_BOTTOM:
+        break;
+    }
+
     seat->pointer.hidden = false;
     seat->mouse.x = x;
     seat->mouse.y = y;
 
     term_xcursor_update_for_seat(term, seat);
 
-    enum term_surface surf_kind = term->active_surface;
-    int button = 0;
-    bool send_to_client = false;
-
     if (tll_length(seat->mouse.buttons) > 0) {
         const struct button_tracker *tracker = &tll_front(seat->mouse.buttons);
         surf_kind = tracker->surf_kind;
@@ -2104,9 +2149,21 @@
 
     switch (surf_kind) {
     case TERM_SURF_NONE:
+        break;
+
     case TERM_SURF_BUTTON_MINIMIZE:
+        if (pointer_is_on_button(term, seat, CSD_SURF_MINIMIZE) != 
is_on_button)
+            render_refresh_csd(term);
+        break;
+
     case TERM_SURF_BUTTON_MAXIMIZE:
+        if (pointer_is_on_button(term, seat, CSD_SURF_MAXIMIZE) != 
is_on_button)
+            render_refresh_csd(term);
+        break;
+
     case TERM_SURF_BUTTON_CLOSE:
+        if (pointer_is_on_button(term, seat, CSD_SURF_CLOSE) != is_on_button)
+            render_refresh_csd(term);
         break;
 
     case TERM_SURF_TITLE:
@@ -2246,8 +2303,8 @@
 }
 
 static const struct key_binding *
- match_mouse_binding(const struct seat *seat, const struct terminal *term,
-                     int button)
+match_mouse_binding(const struct seat *seat, const struct terminal *term,
+                    int button)
 {
     if (seat->wl_keyboard != NULL && seat->kbd.xkb_state != NULL) {
         /* Seat has keyboard - use mouse bindings *with* modifiers */
@@ -2577,12 +2634,19 @@
     }
 
     case TERM_SURF_BUTTON_MINIMIZE:
-        if (button == BTN_LEFT && state == WL_POINTER_BUTTON_STATE_PRESSED)
+        if (button == BTN_LEFT &&
+            pointer_is_on_button(term, seat, CSD_SURF_MINIMIZE) &&
+            state == WL_POINTER_BUTTON_STATE_RELEASED)
+        {
             xdg_toplevel_set_minimized(term->window->xdg_toplevel);
+        }
         break;
 
     case TERM_SURF_BUTTON_MAXIMIZE:
-        if (button == BTN_LEFT && state == WL_POINTER_BUTTON_STATE_PRESSED) {
+        if (button == BTN_LEFT &&
+            pointer_is_on_button(term, seat, CSD_SURF_MAXIMIZE) &&
+            state == WL_POINTER_BUTTON_STATE_RELEASED)
+        {
             if (term->window->is_maximized)
                 xdg_toplevel_unset_maximized(term->window->xdg_toplevel);
             else
@@ -2591,8 +2655,12 @@
         break;
 
     case TERM_SURF_BUTTON_CLOSE:
-        if (button == BTN_LEFT && state == WL_POINTER_BUTTON_STATE_PRESSED)
+        if (button == BTN_LEFT &&
+            pointer_is_on_button(term, seat, CSD_SURF_CLOSE) &&
+            state == WL_POINTER_BUTTON_STATE_RELEASED)
+        {
             term_shutdown(term);
+        }
         break;
 
     case TERM_SURF_GRID: {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/foot-1.18.0/main.c new/foot-1.18.1/main.c
--- old/foot-1.18.0/main.c      2024-08-02 14:28:16.000000000 +0200
+++ new/foot-1.18.1/main.c      2024-08-14 12:00:20.000000000 +0200
@@ -258,7 +258,7 @@
             break;
 
         case 't':
-            tll_push_back(overrides, xstrjoin("term=", optarg, 0));
+            tll_push_back(overrides, xstrjoin("term=", optarg));
             break;
 
         case 'L':
@@ -266,11 +266,11 @@
             break;
 
         case 'T':
-            tll_push_back(overrides, xstrjoin("title=", optarg, 0));
+            tll_push_back(overrides, xstrjoin("title=", optarg));
             break;
 
         case 'a':
-            tll_push_back(overrides, xstrjoin("app-id=", optarg, 0));
+            tll_push_back(overrides, xstrjoin("app-id=", optarg));
             break;
 
         case 'D': {
@@ -284,7 +284,7 @@
         }
 
         case 'f': {
-            char *font_override = xstrjoin("font=", optarg, 0);
+            char *font_override = xstrjoin("font=", optarg);
             tll_push_back(overrides, font_override);
             break;
         }
@@ -425,19 +425,19 @@
          * that does not exist on this system, then the above call may return
          * NULL. We should just continue with the fallback method below.
          */
-        LOG_WARN("setlocale() failed");
-        locale = "C";
+        LOG_ERR("setlocale() failed. The most common cause is that the "
+                "configured locale is not available, or has been misspelled");
     }
 
-    LOG_INFO("locale: %s", locale);
+    LOG_INFO("locale: %s", locale != NULL ? locale : "<invalid>");
 
-    bool bad_locale = !locale_is_utf8();
+    bool bad_locale = locale == NULL || !locale_is_utf8();
     if (bad_locale) {
         static const char fallback_locales[][12] = {
             "C.UTF-8",
             "en_US.UTF-8",
         };
-        char *saved_locale = xstrdup(locale);
+        char *saved_locale = locale != NULL ? xstrdup(locale) : NULL;
 
         /*
          * Try to force an UTF-8 locale. If we succeed, launch the
@@ -448,13 +448,23 @@
             const char *const fallback_locale = fallback_locales[i];
 
             if (setlocale(LC_CTYPE, fallback_locale) != NULL) {
-                LOG_WARN("'%s' is not a UTF-8 locale, using '%s' instead",
-                         saved_locale, fallback_locale);
-
-                user_notification_add_fmt(
-                    &user_notifications, USER_NOTIFICATION_WARNING,
-                    "'%s' is not a UTF-8 locale, using '%s' instead",
-                    saved_locale, fallback_locale);
+                if (saved_locale != NULL) {
+                    LOG_WARN(
+                        "'%s' is not a UTF-8 locale, falling back to '%s'",
+                        saved_locale, fallback_locale);
+
+                    user_notification_add_fmt(
+                        &user_notifications, USER_NOTIFICATION_WARNING,
+                        "'%s' is not a UTF-8 locale, falling back to '%s'",
+                        saved_locale, fallback_locale);
+
+                } else {
+                    LOG_WARN(
+                        "invalid locale, falling back to '%s'", 
fallback_locale);
+                    user_notification_add_fmt(
+                        &user_notifications, USER_NOTIFICATION_WARNING,
+                        "invalid locale, falling back to '%s'", 
fallback_locale);
+                }
 
                 bad_locale = false;
                 break;
@@ -462,14 +472,22 @@
         }
 
         if (bad_locale) {
-            LOG_ERR(
-                "'%s' is not a UTF-8 locale, and failed to find a fallback",
-                saved_locale);
-
-            user_notification_add_fmt(
-                &user_notifications, USER_NOTIFICATION_ERROR,
-                "'%s' is not a UTF-8 locale, and failed to find a fallback",
-                saved_locale);
+            if (saved_locale != NULL) {
+                LOG_ERR(
+                    "'%s' is not a UTF-8 locale, and failed to find a 
fallback",
+                    saved_locale);
+
+                user_notification_add_fmt(
+                    &user_notifications, USER_NOTIFICATION_ERROR,
+                    "'%s' is not a UTF-8 locale, and failed to find a 
fallback",
+                    saved_locale);
+            } else {
+                LOG_ERR("invalid locale, and failed to find a fallback");
+
+                user_notification_add_fmt(
+                    &user_notifications, USER_NOTIFICATION_ERROR,
+                    "invalid locale, and failed to find a fallback");
+            }
         }
         free(saved_locale);
     }
@@ -658,15 +676,19 @@
 
 UNITTEST
 {
-    char *s = xstrjoin("foo", "bar", 0);
+    char *s = xstrjoin("foo", "bar");
     xassert(streq(s, "foobar"));
     free(s);
 
-    s = xstrjoin("foo", "bar", ' ');
+    s = xstrjoin3("foo", " ", "bar");
     xassert(streq(s, "foo bar"));
     free(s);
 
-    s = xstrjoin("foo", "bar", ',');
+    s = xstrjoin3("foo", ",", "bar");
     xassert(streq(s, "foo,bar"));
     free(s);
+
+    s = xstrjoin3("foo", "bar", "baz");
+    xassert(streq(s, "foobarbaz"));
+    free(s);
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/foot-1.18.0/meson.build new/foot-1.18.1/meson.build
--- old/foot-1.18.0/meson.build 2024-08-02 14:28:16.000000000 +0200
+++ new/foot-1.18.1/meson.build 2024-08-14 12:00:20.000000000 +0200
@@ -1,5 +1,5 @@
 project('foot', 'c',
-        version: '1.18.0',
+        version: '1.18.1',
         license: 'MIT',
         meson_version: '>=0.59.0',
         default_options: [
@@ -12,12 +12,16 @@
 
 cc = meson.get_compiler('c')
 
-if cc.has_function('memfd_create')
+if cc.has_function('memfd_create',
+                   args: ['-D_GNU_SOURCE'],
+                   prefix: '#include <sys/mman.h>')
   add_project_arguments('-DMEMFD_CREATE', language: 'c')
 endif
 
 # Missing on DragonFly, FreeBSD < 14.1
-if cc.has_function('execvpe')
+if cc.has_function('execvpe',
+                   args: ['-D_GNU_SOURCE'],
+                   prefix: '#include <unistd.h>')
   add_project_arguments('-DEXECVPE', language: 'c')
 endif
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/foot-1.18.0/notify.c new/foot-1.18.1/notify.c
--- old/foot-1.18.0/notify.c    2024-08-02 14:28:16.000000000 +0200
+++ new/foot-1.18.1/notify.c    2024-08-14 12:00:20.000000000 +0200
@@ -34,6 +34,7 @@
     free(notif->icon_cache_id);
     free(notif->icon_symbolic_name);
     free(notif->icon_data);
+    free(notif->sound_name);
     free(notif->xdg_token);
     free(notif->stdout_data);
 
@@ -77,7 +78,7 @@
 
     LOG_DBG("wrote icon data to %s", name);
     *filename = xstrdup(name);
-    *symbolic_name = xasprintf("file://%s", *filename);
+    *symbolic_name = xstrjoin("file://", *filename);
     return true;
 }
 
@@ -421,9 +422,12 @@
                 ? "normal" : "critical";
 
     LOG_DBG("notify: title=\"%s\", body=\"%s\", app-id=\"%s\", 
category=\"%s\", "
-            "urgency=\"%s\", icon=\"%s\", expires=%d, replaces=%u (tracking: 
%s)",
+            "urgency=\"%s\", icon=\"%s\", expires=%d, replaces=%u, muted=%s, "
+            "sound-name=%s (tracking: %s)",
             title, body, app_id, notif->category, urgency_str, 
icon_name_or_path,
-            notif->expire_time, replaces_id, track_notification ? "yes" : 
"no");
+            notif->expire_time, replaces_id,
+            notif->muted ? "yes" : "no", notif->sound_name,
+            track_notification ? "yes" : "no");
 
     xassert(title != NULL);
     if (title == NULL)
@@ -463,13 +467,16 @@
     }
 
     if (!spawn_expand_template(
-        &term->conf->desktop_notifications.command, 10,
+        &term->conf->desktop_notifications.command, 12,
         (const char *[]){
             "app-id", "window-title", "icon", "title", "body", "category",
-            "urgency", "expire-time", "replace-id", "action-argument"},
+            "urgency", "muted", "sound-name", "expire-time", "replace-id",
+            "action-argument"},
         (const char *[]){
             app_id, term->window_title, icon_name_or_path, title, body,
             notif->category != NULL ? notif->category : "", urgency_str,
+            notif->muted ? "true" : "false",
+            notif->sound_name != NULL ? notif->sound_name : "",
             expire_time, replaces_id_str,
 
             /* Custom expansion below, since we need to expand to multiple 
arguments */
@@ -542,6 +549,7 @@
             notif->icon_data = NULL;
             notif->icon_data_sz = 0;
             notif->icon_path = NULL;
+            notif->sound_name = NULL;
             notif->icon_fd = -1;
             notif->stdout_fd = -1;
             struct notification *new_notif = 
&tll_back(term->active_notifications);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/foot-1.18.0/notify.h new/foot-1.18.1/notify.h
--- old/foot-1.18.0/notify.h    2024-08-02 14:28:16.000000000 +0200
+++ new/foot-1.18.1/notify.h    2024-08-14 12:00:20.000000000 +0200
@@ -52,6 +52,9 @@
     bool report_activated;  /* OSC-99: report notification activation to 
client */
     bool report_closed;     /* OSC-99: report notification closed to client */
 
+    bool muted;            /* Explicitly mute the notification */
+    char *sound_name;      /* Should be set to NULL if muted == true */
+
     /*
      * Used internally by notify
      */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/foot-1.18.0/osc.c new/foot-1.18.1/osc.c
--- old/foot-1.18.0/osc.c       2024-08-02 14:28:16.000000000 +0200
+++ new/foot-1.18.1/osc.c       2024-08-14 12:00:20.000000000 +0200
@@ -564,6 +564,33 @@
     });
 }
 
+IGNORE_WARNING("-Wpedantic")
+static bool
+verify_kitty_id_is_valid(const char *id)
+{
+    const size_t len = strlen(id);
+
+    for (size_t i = 0; i < len; i++) {
+        switch (id[i]) {
+        case 'a' ... 'z':
+        case 'A' ... 'Z':
+        case '0' ... '9':
+        case '_':
+        case '-':
+        case '+':
+        case '.':
+            break;
+
+        default:
+            return false;
+        }
+    }
+
+    return true;
+}
+UNIGNORE_WARNINGS
+
+
 static void
 kitty_notification(struct terminal *term, char *string)
 {
@@ -582,6 +609,7 @@
     char *icon_cache_id = NULL;    /* The 'g' parameter */
     char *symbolic_icon = NULL;    /* The 'n' parameter */
     char *category = NULL;         /* The 't' parameter */
+    char *sound_name = NULL;       /* The 's' parameter */
     char *payload = NULL;
 
     bool focus = true;             /* The 'a' parameter */
@@ -672,8 +700,11 @@
 
         case 'i':
             /* id */
-            free(id);
-            id = xstrdup(value);
+            if (verify_kitty_id_is_valid(value)) {
+                free(id);
+                id = xstrdup(value);
+            } else
+                LOG_WARN("OSC-99: ignoring invalid 'i' identifier");
             break;
 
         case 'p':
@@ -709,7 +740,7 @@
                 char reply[128];
                 int n = xsnprintf(
                     reply, sizeof(reply),
-                    "\033]99;i=%s:p=?;p=%s:a=%s:o=%s:u=%s:c=1:w=1%s",
+                    
"\033]99;i=%s:p=?;p=%s:a=%s:o=%s:u=%s:c=1:w=1:s=system,silent,error,warn,warning,info,question%s",
                     reply_id, p_caps, a_caps, when_caps, u_caps, terminator);
 
                 xassert(n < sizeof(reply));
@@ -753,10 +784,15 @@
             break;
         }
 
-        case 'f':
-            free(app_id);
-            app_id = base64_decode(value, NULL);
+        case 'f': {
+            /* App-name */
+            char *decoded = base64_decode(value, NULL);
+            if (decoded != NULL) {
+                free(app_id);
+                app_id = decoded;
+            }
             break;
+        }
 
         case 't': {
             /* Type (category) */
@@ -767,7 +803,7 @@
                 else {
                     /* Append, comma separated */
                     char *old_category = category;
-                    category = xstrjoin(old_category, decoded, ',');
+                    category = xstrjoin3(old_category, ",", decoded);
                     free(decoded);
                     free(old_category);
                 }
@@ -775,6 +811,32 @@
             break;
         }
 
+        case 's': {
+            /* Sound */
+            char *decoded = base64_decode(value, NULL);
+            if (decoded != NULL) {
+                free(sound_name);
+                sound_name = decoded;
+
+                const char *translated_name = NULL;
+
+                if (streq(decoded, "error"))
+                    translated_name = "dialog-error";
+                else if (streq(decoded, "warn") || streq(decoded, "warning"))
+                    translated_name = "dialog-warning";
+                else if (streq(decoded, "info"))
+                    translated_name = "dialog-information";
+                else if (streq(decoded, "question"))
+                    translated_name = "dialog-question";
+
+                if (translated_name != NULL) {
+                    free(sound_name);
+                    sound_name = xstrdup(translated_name);
+                }
+            }
+            break;
+        }
+
         case 'g':
             /* graphical ID (see 'n' and 'p=icon') */
             free(icon_cache_id);
@@ -910,12 +972,25 @@
             category = NULL;  /* Prevent double free */
         } else {
             /* Append, comma separated */
-            char *new_category = xstrjoin(notif->category, category, ',');
+            char *new_category = xstrjoin3(notif->category, ",", category);
             free(notif->category);
             notif->category = new_category;
         }
     }
 
+    if (sound_name != NULL) {
+        notif->muted = streq(sound_name, "silent");
+
+        if (notif->muted || streq(sound_name, "system")) {
+            free(notif->sound_name);
+            notif->sound_name = NULL;
+        } else {
+            free(notif->sound_name);
+            notif->sound_name = sound_name;
+            sound_name = NULL;  /* Prevent double free */
+        }
+    }
+
     /* Handled chunked payload - append to existing metadata */
     switch (payload_type) {
     case PAYLOAD_TITLE:
@@ -929,7 +1004,7 @@
             payload = NULL;
         } else {
             char *old = *ptr;
-            *ptr = xstrjoin(old, payload, 0);
+            *ptr = xstrjoin(old, payload);
             free(old);
         }
         break;
@@ -963,7 +1038,7 @@
                 tll_push_back(notif->actions, xstrdup(button));
             }
         }
-        
+
         break;
     }
     }
@@ -1002,7 +1077,7 @@
                     alive_ids = xstrdup(item_id);
                 else {
                     char *old_alive_ids = alive_ids;
-                    alive_ids = xstrjoin(old_alive_ids, item_id, ',');
+                    alive_ids = xstrjoin3(old_alive_ids, ",", item_id);
                     free(old_alive_ids);
                 }
             }
@@ -1037,6 +1112,7 @@
     free(symbolic_icon);
     free(payload);
     free(category);
+    free(sound_name);
 }
 
 void
@@ -1305,13 +1381,22 @@
         term_damage_color(term, COLOR_DEFAULT, 0);
         break;
 
-    case 111: /* Reset default text background color */
+    case 111: { /* Reset default text background color */
         LOG_DBG("resetting background color");
+        bool alpha_changed = term->colors.alpha != term->conf->colors.alpha;
+
         term->colors.bg = term->conf->colors.bg;
         term->colors.alpha = term->conf->colors.alpha;
+
+        if (alpha_changed) {
+            wayl_win_alpha_changed(term->window);
+            term_font_subpixel_changed(term);
+        }
+
         term_damage_color(term, COLOR_DEFAULT, 0);
         term_damage_margins(term);
         break;
+    }
 
     case 112:
         LOG_DBG("resetting cursor color");
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/foot-1.18.0/render.c new/foot-1.18.1/render.c
--- old/foot-1.18.0/render.c    2024-08-02 14:28:16.000000000 +0200
+++ new/foot-1.18.1/render.c    2024-08-14 12:00:20.000000000 +0200
@@ -2627,6 +2627,32 @@
     pixman_image_unref(src);
 }
 
+static bool
+any_pointer_is_on_button(const struct terminal *term, enum csd_surface 
csd_surface)
+{
+    if (unlikely(tll_length(term->wl->seats) == 0))
+        return false;
+
+    tll_foreach(term->wl->seats, it) {
+        const struct seat *seat = &it->item;
+
+        if (seat->mouse.x < 0)
+            continue;
+        if (seat->mouse.y < 0)
+            continue;
+
+        struct csd_data info = get_csd_data(term, csd_surface);
+        if (seat->mouse.x > info.width)
+            continue;
+
+        if (seat->mouse.y > info.height)
+            continue;
+        return true;
+    }
+
+    return false;
+}
+
 static void
 render_csd_button(struct terminal *term, enum csd_surface surf_idx,
                   const struct csd_data *info, struct buffer *buf)
@@ -2650,21 +2676,24 @@
         _color = term->conf->colors.table[4];  /* blue */
         is_set = term->conf->csd.color.minimize_set;
         conf_color = &term->conf->csd.color.minimize;
-        is_active = term->active_surface == TERM_SURF_BUTTON_MINIMIZE;
+        is_active = term->active_surface == TERM_SURF_BUTTON_MINIMIZE &&
+                    any_pointer_is_on_button(term, CSD_SURF_MINIMIZE);
         break;
 
     case CSD_SURF_MAXIMIZE:
         _color = term->conf->colors.table[2];  /* green */
         is_set = term->conf->csd.color.maximize_set;
         conf_color = &term->conf->csd.color.maximize;
-        is_active = term->active_surface == TERM_SURF_BUTTON_MAXIMIZE;
+        is_active = term->active_surface == TERM_SURF_BUTTON_MAXIMIZE &&
+                    any_pointer_is_on_button(term, CSD_SURF_MAXIMIZE);
         break;
 
     case CSD_SURF_CLOSE:
         _color = term->conf->colors.table[1];  /* red */
         is_set = term->conf->csd.color.close_set;
         conf_color = &term->conf->csd.color.quit;
-        is_active = term->active_surface == TERM_SURF_BUTTON_CLOSE;
+        is_active = term->active_surface == TERM_SURF_BUTTON_CLOSE &&
+                    any_pointer_is_on_button(term, CSD_SURF_CLOSE);
         break;
 
     default:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/foot-1.18.0/slave.c new/foot-1.18.1/slave.c
--- old/foot-1.18.0/slave.c     2024-08-02 14:28:16.000000000 +0200
+++ new/foot-1.18.1/slave.c     2024-08-14 12:00:20.000000000 +0200
@@ -55,7 +55,7 @@
          path != NULL;
          path = strtok(NULL, ":"))
     {
-        char *full = xasprintf("%s/%s", path, file);
+        char *full = xstrjoin3(path, "/", file);
         if (access(full, F_OK) == 0) {
             free(path_list);
             return full;
@@ -158,6 +158,7 @@
     xassert(prefix != NULL);
 
     if (write(fd, prefix, strlen(prefix)) < 0 ||
+        write(fd, "foot: ", 6) < 0 ||
         write(fd, notif->text, strlen(notif->text)) < 0 ||
         write(fd, postfix, strlen(postfix)) < 0)
     {
@@ -180,7 +181,8 @@
 }
 
 static bool
-emit_notifications_of_kind(int fd, const user_notifications_t *notifications,
+emit_notifications_of_kind(int fd,
+                           const user_notifications_t *notifications,
                            enum user_notification_kind kind)
 {
     tll_foreach(*notifications, it) {
@@ -329,7 +331,7 @@
     if (env->envp == NULL)
         setenv(name, value, 1);
     else {
-        char *e = xasprintf("%s=%s", name, value);
+        char *e = xstrjoin3(name, "=", value);
 
         /* Search for existing variable. If found, replace it with the
            new value */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/foot-1.18.0/terminal.c new/foot-1.18.1/terminal.c
--- old/foot-1.18.0/terminal.c  2024-08-02 14:28:16.000000000 +0200
+++ new/foot-1.18.1/terminal.c  2024-08-14 12:00:20.000000000 +0200
@@ -994,7 +994,7 @@
                 snprintf(size, sizeof(size), ":size=%.2f",
                          term->font_sizes[i][j].pt_size * scale);
 
-            names[i][j] = xstrjoin(font->pattern, size, 0);
+            names[i][j] = xstrjoin(font->pattern, size);
         }
     }
 
@@ -1021,9 +1021,9 @@
 
     char *attrs[4] = {
         [0] = dpi, /* Takes ownership */
-        [1] = xstrjoin(dpi, !custom_bold ? ":weight=bold" : "", 0),
-        [2] = xstrjoin(dpi, !custom_italic ? ":slant=italic" : "", 0),
-        [3] = xstrjoin(dpi, !custom_bold_italic ? ":weight=bold:slant=italic" 
: "", 0),
+        [1] = xstrjoin(dpi, !custom_bold ? ":weight=bold" : ""),
+        [2] = xstrjoin(dpi, !custom_italic ? ":slant=italic" : ""),
+        [3] = xstrjoin(dpi, !custom_bold_italic ? ":weight=bold:slant=italic" 
: ""),
     };
 
     struct fcft_font *fonts[4];
@@ -1048,8 +1048,10 @@
     for (size_t i = 0; i < 4; i++) {
         if (tids[i] != 0) {
             int ret;
-            thrd_join(tids[i], &ret);
-            success = success && ret;
+            if (thrd_join(tids[i], &ret) != 0)
+                success = false;
+            else
+                success = success && ret;
         } else
             success = false;
     }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/foot-1.18.0/utils/xtgettcap.c 
new/foot-1.18.1/utils/xtgettcap.c
--- old/foot-1.18.0/utils/xtgettcap.c   2024-08-02 14:28:16.000000000 +0200
+++ new/foot-1.18.1/utils/xtgettcap.c   2024-08-14 12:00:20.000000000 +0200
@@ -141,6 +141,9 @@
                 const char *key = strtok(key_value, "=");
                 const char *value = strtok(NULL, "=");
 
+                if (key == NULL)
+                    continue;
+
 #if 0
                 assert((success && value != NULL) ||
                        (!success && value == NULL));
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/foot-1.18.0/xmalloc.h new/foot-1.18.1/xmalloc.h
--- old/foot-1.18.0/xmalloc.h   2024-08-02 14:28:16.000000000 +0200
+++ new/foot-1.18.1/xmalloc.h   2024-08-14 12:00:20.000000000 +0200
@@ -25,16 +25,25 @@
 }
 
 static inline char *
-xstrjoin(const char *s1, const char *s2, char delim)
+xstrjoin(const char *s1, const char *s2)
 {
     size_t n1 = strlen(s1);
-    size_t n2 = delim > 0 ? 1 : 0;
-    size_t n3 = strlen(s2);
+    size_t n2 = strlen(s2);
+    char *joined = xmalloc(n1 + n2 + 1);
+    memcpy(joined, s1, n1);
+    memcpy(joined + n1, s2, n2 + 1);
+    return joined;
+}
 
+static inline char *
+xstrjoin3(const char *s1, const char *s2, const char *s3)
+{
+    size_t n1 = strlen(s1);
+    size_t n2 = strlen(s2);
+    size_t n3 = strlen(s3);
     char *joined = xmalloc(n1 + n2 + n3 + 1);
     memcpy(joined, s1, n1);
-    if (delim > 0)
-        joined[n1] = delim;
-    memcpy(joined + n1 + n2, s2, n3 + 1);
+    memcpy(joined + n1, s2, n2);
+    memcpy(joined + n1 + n2, s3, n3 + 1);
     return joined;
 }

Reply via email to