Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package imv for openSUSE:Factory checked in 
at 2024-02-21 17:57:48
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/imv (Old)
 and      /work/SRC/openSUSE:Factory/.imv.new.1706 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "imv"

Wed Feb 21 17:57:48 2024 rev:8 rq:1148402 version:4.5.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/imv/imv.changes  2023-01-21 19:10:26.968917666 
+0100
+++ /work/SRC/openSUSE:Factory/.imv.new.1706/imv.changes        2024-02-21 
17:57:56.230602868 +0100
@@ -1,0 +2,13 @@
+Wed Feb 21 06:30:43 UTC 2024 - Michael Vetter <[email protected]>
+
+- Update to 4.5.0:
+  * Add new jpgxl backend
+  * Added -W and -H arguments to configure initial dimensions
+  * Fix utf8 in window titles
+  * Fix some animated gifs showing as still images
+  * Fix several crashes
+  * Fixed new build warnings
+  * Limit libnsgif to <1.0.0 to fix build
+  * Update mime types
+
+-------------------------------------------------------------------

Old:
----
  v4.4.0.tar.gz

New:
----
  v4.5.0.tar.gz

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

Other differences:
------------------
++++++ imv.spec ++++++
--- /var/tmp/diff_new_pack.Aox9qu/_old  2024-02-21 17:57:56.682619213 +0100
+++ /var/tmp/diff_new_pack.Aox9qu/_new  2024-02-21 17:57:56.682619213 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package imv
 #
-# Copyright (c) 2023 SUSE LLC
+# Copyright (c) 2024 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -17,7 +17,7 @@
 
 
 Name:           imv
-Version:        4.4.0
+Version:        4.5.0
 Release:        0
 Summary:        Image viewer for X11/Wayland
 License:        GPL-2.0-or-later AND MIT
@@ -36,6 +36,7 @@
 BuildRequires:  pkgconfig(fontconfig)
 BuildRequires:  pkgconfig(libheif)
 BuildRequires:  pkgconfig(libjpeg)
+BuildRequires:  pkgconfig(libjxl)
 BuildRequires:  pkgconfig(libpng16)
 BuildRequires:  pkgconfig(librsvg-2.0) >= 2.44
 BuildRequires:  pkgconfig(libtiff-4)

++++++ v4.4.0.tar.gz -> v4.5.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/imv-v4.4.0/.builds/archlinux.yml 
new/imv-v4.5.0/.builds/archlinux.yml
--- old/imv-v4.4.0/.builds/archlinux.yml        2023-01-18 23:20:52.000000000 
+0100
+++ new/imv-v4.5.0/.builds/archlinux.yml        2024-02-20 23:30:06.000000000 
+0100
@@ -10,7 +10,7 @@
   - libheif
   - libinih
   - libjpeg-turbo
-  - libnsgif
+  - libjxl
   - libpng
   - librsvg
   - libtiff
@@ -24,9 +24,10 @@
 sources:
   - https://git.sr.ht/~exec64/imv
 tasks:
+  # arch ships libnsgif 1.0.0 which is too new
   - gcc: |
-      CC=gcc meson imv build_gcc -D auto_features=enabled
+      CC=gcc meson imv build_gcc -D auto_features=enabled -D libnsgif=disabled
       CC=gcc ninja -C build_gcc test
   - clang: |
-      CC=clang meson imv build_clang -D auto_features=enabled
+      CC=clang meson imv build_clang -D auto_features=enabled -D 
libnsgif=disabled
       CC=clang ninja -C build_clang test
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/imv-v4.4.0/.builds/debian.yml 
new/imv-v4.5.0/.builds/debian.yml
--- old/imv-v4.4.0/.builds/debian.yml   2023-01-18 23:20:52.000000000 +0100
+++ new/imv-v4.5.0/.builds/debian.yml   2024-02-20 23:30:06.000000000 +0100
@@ -9,6 +9,7 @@
   - libheif-dev
   - libicu-dev
   - libinih-dev
+  - libjxl-dev
   - libpango1.0-dev
   - libpng-dev
   - librsvg2-dev
@@ -24,16 +25,10 @@
 sources:
   - https://git.sr.ht/~exec64/imv
 tasks:
-  - dummy: |
-      true
-#FIXME:
-# the old meson package in debian has a bug and crashes with
-# our meson.build; re-enable this once debian packages a version
-# newer than 0.49.2
-      # libnsgif isn't packaged by debian
-# - gcc: |
-#     CC=gcc meson imv build_gcc -D auto_features=enabled -D libnsgif=disabled
-#     CC=gcc ninja -C build_gcc test
-# - clang: |
-#     CC=clang meson imv build_clang -D auto_features=enabled -D 
libnsgif=disabled
-#     CC=clang ninja -C build_clang test
+  # libnsgif isn't packaged by debian
+  - gcc: |
+      CC=gcc meson imv build_gcc -D auto_features=enabled -D libnsgif=disabled
+      CC=gcc ninja -C build_gcc test
+  - clang: |
+      CC=clang meson imv build_clang -D auto_features=enabled -D 
libnsgif=disabled
+      CC=clang ninja -C build_clang test
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/imv-v4.4.0/.builds/fedora.yml 
new/imv-v4.5.0/.builds/fedora.yml
--- old/imv-v4.4.0/.builds/fedora.yml   2023-01-18 23:20:52.000000000 +0100
+++ new/imv-v4.5.0/.builds/fedora.yml   2024-02-20 23:30:06.000000000 +0100
@@ -6,7 +6,9 @@
   - inih
   - libX11-devel
   - libcmocka-devel
+  - libheif-devel
   - libicu-devel
+  - libjxl-devel
   - libpng-devel
   - librsvg2-devel
   - libtiff-devel
@@ -23,11 +25,10 @@
 sources:
   - https://git.sr.ht/~exec64/imv
 tasks:
-  # libheif ins't packaged by fedora
   # libnsgif isn't packaged by fedora
   - gcc: |
-      CC=gcc meson imv build_gcc -D auto_features=enabled -D libheif=disabled 
-D libnsgif=disabled
+      CC=gcc meson imv build_gcc -D auto_features=enabled -D libnsgif=disabled
       CC=gcc ninja -C build_gcc test
   - clang: |
-      CC=clang meson imv build_clang -D auto_features=enabled -D 
libheif=disabled -D libnsgif=disabled
+      CC=clang meson imv build_clang -D auto_features=enabled -D 
libnsgif=disabled
       CC=clang ninja -C build_clang test
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/imv-v4.4.0/.builds/freebsd.yml 
new/imv-v4.5.0/.builds/freebsd.yml
--- old/imv-v4.4.0/.builds/freebsd.yml  2023-01-18 23:20:52.000000000 +0100
+++ new/imv-v4.5.0/.builds/freebsd.yml  2024-02-20 23:30:06.000000000 +0100
@@ -7,7 +7,7 @@
   - graphics/libGLU
   - graphics/libheif
   - graphics/libjpeg-turbo
-  - graphics/libnsgif
+  - graphics/libjxl
   - graphics/librsvg2-rust
   - graphics/png
   - graphics/tiff
@@ -19,6 +19,7 @@
 sources:
   - https://git.sr.ht/~exec64/imv
 tasks:
+  # freebsd ships libnsgif 1.0.0 which is too new
   - meson: |
-      meson imv build -D auto_features=enabled -D 
c_link_args='-L/usr/local/lib'
+      meson imv build -D auto_features=enabled -D libnsgif=disabled -D 
c_link_args='-L/usr/local/lib'
       ninja -C build test
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/imv-v4.4.0/.builds/ubuntu.yml 
new/imv-v4.5.0/.builds/ubuntu.yml
--- old/imv-v4.4.0/.builds/ubuntu.yml   2023-01-18 23:20:52.000000000 +0100
+++ new/imv-v4.5.0/.builds/ubuntu.yml   2024-02-20 23:30:06.000000000 +0100
@@ -25,9 +25,10 @@
   - https://git.sr.ht/~exec64/imv
 tasks:
   # libnsgif isn't packaged by ubuntu
+  # libjxl-dev isn't packaged by ubuntu lts
   - gcc: |
-      CC=gcc meson imv build_gcc -D auto_features=enabled -D libnsgif=disabled
+      CC=gcc meson imv build_gcc -D auto_features=enabled -D libnsgif=disabled 
-D libjxl=disabled
       CC=gcc ninja -C build_gcc test
   - clang: |
-      CC=clang meson imv build_clang -D auto_features=enabled -D 
libnsgif=disabled
+      CC=clang meson imv build_clang -D auto_features=enabled -D 
libnsgif=disabled -D libjxl=disabled
       CC=clang ninja -C build_clang test
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/imv-v4.4.0/AUTHORS new/imv-v4.5.0/AUTHORS
--- old/imv-v4.4.0/AUTHORS      2023-01-18 23:20:52.000000000 +0100
+++ new/imv-v4.5.0/AUTHORS      2024-02-20 23:30:06.000000000 +0100
@@ -8,6 +8,7 @@
  * Jose Diez
  * Kenneth Hanley
  * Julian Heinzel
+ * Fabio Henrique
  * Hannes Körber
  * Aleksandra Kosiacka
  * Michal Koutenský
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/imv-v4.4.0/CHANGELOG new/imv-v4.5.0/CHANGELOG
--- old/imv-v4.4.0/CHANGELOG    2023-01-18 23:20:52.000000000 +0100
+++ new/imv-v4.5.0/CHANGELOG    2024-02-20 23:30:06.000000000 +0100
@@ -1,6 +1,18 @@
 imv Changelog
 =============
 
+v4.5.0 - 2024-02-20
+-------------------
+
+* Add new jpgxl backend
+* Added -W and -H arguments to configure initial dimensions
+* Fix utf8 in window titles
+* Fix some animated gifs showing as still images
+* Fix several crashes
+* Fixed new build warnings
+* Limit libnsgif to <1.0.0 to fix build
+* Update mime types
+
 v4.4.0 - 2023-01-18
 -------------------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/imv-v4.4.0/README.md new/imv-v4.5.0/README.md
--- old/imv-v4.4.0/README.md    2023-01-18 23:20:52.000000000 +0100
+++ new/imv-v4.5.0/README.md    2024-02-20 23:30:06.000000000 +0100
@@ -139,6 +139,7 @@
 | librsvg        | >=v2.44  | Optional. Provides SVG support.                |
 | libnsgif       |          | Optional. Provides animated GIF support.       |
 | libheif        |          | Optional. Provides HEIF support.               |
+| libjxl         |          | Optional. Provides JPEGXL support.             |
 
 Dependencies are determined by which backends and window systems are enabled
 when building `imv`. You can find a summary of which backends are available
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/imv-v4.4.0/doc/imv.1.txt new/imv-v4.5.0/doc/imv.1.txt
--- old/imv-v4.4.0/doc/imv.1.txt        2023-01-18 23:20:52.000000000 +0100
+++ new/imv-v4.5.0/doc/imv.1.txt        2024-02-20 23:30:06.000000000 +0100
@@ -76,6 +76,12 @@
 *-x*::
        Disable looping of input paths.
 
+*-W* <width>::
+       Initial width of window.
+
+*-H* <height>::
+       Initial height of window.
+
 Commands
 --------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/imv-v4.4.0/files/imv-dir.desktop 
new/imv-v4.5.0/files/imv-dir.desktop
--- old/imv-v4.4.0/files/imv-dir.desktop        2023-01-18 23:20:52.000000000 
+0100
+++ new/imv-v4.5.0/files/imv-dir.desktop        2024-02-20 23:30:06.000000000 
+0100
@@ -9,6 +9,6 @@
 Terminal=false
 Type=Application
 Categories=Graphics;2DGraphics;Viewer;
-MimeType=image/bmp;image/gif;image/jpeg;image/jpg;image/pjpeg;image/png;image/tiff;image/x-bmp;image/x-pcx;image/x-png;image/x-portable-anymap;image/x-portable-bitmap;image/x-portable-graymap;image/x-portable-pixmap;image/x-tga;image/x-xbitmap;
+MimeType=image/bmp;image/gif;image/jpeg;image/jpg;image/pjpeg;image/png;image/tiff;image/x-bmp;image/x-pcx;image/x-png;image/x-portable-anymap;image/x-portable-bitmap;image/x-portable-graymap;image/x-portable-pixmap;image/x-tga;image/x-xbitmap;image/heif;image/avif
 Icon=multimedia-photo-viewer
 Keywords=photo;picture;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/imv-v4.4.0/files/imv.desktop 
new/imv-v4.5.0/files/imv.desktop
--- old/imv-v4.4.0/files/imv.desktop    2023-01-18 23:20:52.000000000 +0100
+++ new/imv-v4.5.0/files/imv.desktop    2024-02-20 23:30:06.000000000 +0100
@@ -8,7 +8,7 @@
 Terminal=false
 Type=Application
 Categories=Graphics;2DGraphics;Viewer;
-MimeType=image/bmp;image/gif;image/jpeg;image/jpg;image/pjpeg;image/png;image/tiff;image/x-bmp;image/x-pcx;image/x-png;image/x-portable-anymap;image/x-portable-bitmap;image/x-portable-graymap;image/x-portable-pixmap;image/x-tga;image/x-xbitmap;image/heif
+MimeType=image/bmp;image/gif;image/jpeg;image/jpg;image/pjpeg;image/png;image/tiff;image/x-bmp;image/x-pcx;image/x-png;image/x-portable-anymap;image/x-portable-bitmap;image/x-portable-graymap;image/x-portable-pixmap;image/x-tga;image/x-xbitmap;image/heif;image/avif
 Name[en_US]=imv
 Icon=multimedia-photo-viewer
 Keywords=photo;picture;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/imv-v4.4.0/meson.build new/imv-v4.5.0/meson.build
--- old/imv-v4.4.0/meson.build  2023-01-18 23:20:52.000000000 +0100
+++ new/imv-v4.5.0/meson.build  2024-02-20 23:30:06.000000000 +0100
@@ -1,7 +1,7 @@
 project(
   'imv',
   ['c'],
-  version: '4.4.0',
+  version: '4.5.0',
   license: 'MIT',
   meson_version: '>= 0.47',
   default_options: ['buildtype=debugoptimized', 'c_std=c99'],
@@ -125,8 +125,9 @@
   ['libpng', 'dependency', 'libpng', []],
   ['libjpeg', 'dependency', 'libturbojpeg', []],
   ['librsvg', 'dependency', 'librsvg-2.0', '>= 2.44'],
-  ['libnsgif', 'dependency', 'libnsgif', []],
+  ['libnsgif', 'dependency', 'libnsgif', '< 1.0.0'],
   ['libheif', 'dependency', 'libheif', []],
+  ['libjxl', 'dependency', 'libjxl', []],
 ]
   _backend_name = backend[0]
   _dep_type = backend[1]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/imv-v4.4.0/meson_options.txt 
new/imv-v4.5.0/meson_options.txt
--- old/imv-v4.4.0/meson_options.txt    2023-01-18 23:20:52.000000000 +0100
+++ new/imv-v4.5.0/meson_options.txt    2024-02-20 23:30:06.000000000 +0100
@@ -89,3 +89,11 @@
   type : 'feature',
   description : 'provides: heif'
 )
+
+# libjxl https://jpeg.org/jpegxl/
+# depends: brotlidec, brotlienc, highway, lcms2
+# license: modified bsd
+option('libjxl',
+  type : 'feature',
+  description : 'provides: jxl'
+)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/imv-v4.4.0/src/backend_freeimage.c 
new/imv-v4.5.0/src/backend_freeimage.c
--- old/imv-v4.4.0/src/backend_freeimage.c      2023-01-18 23:20:52.000000000 
+0100
+++ new/imv-v4.5.0/src/backend_freeimage.c      2024-02-20 23:30:06.000000000 
+0100
@@ -139,7 +139,8 @@
     FreeImage_GetMetadata(FIMD_ANIMATION, frame, "FrameTime", &tag);
     if (FreeImage_GetTagValue(tag)) {
       *frametime = *(int*)FreeImage_GetTagValue(tag);
-    } else {
+    }
+    if (*frametime == 0) {
       *frametime = 100; /* default value for gifs */
     }
     bmp = FreeImage_ConvertTo24Bits(frame);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/imv-v4.4.0/src/backend_libjxl.c 
new/imv-v4.5.0/src/backend_libjxl.c
--- old/imv-v4.4.0/src/backend_libjxl.c 1970-01-01 01:00:00.000000000 +0100
+++ new/imv-v4.5.0/src/backend_libjxl.c 2024-02-20 23:30:06.000000000 +0100
@@ -0,0 +1,282 @@
+#include "backend.h"
+#include "bitmap.h"
+#include "image.h"
+#include "log.h"
+#include "source.h"
+#include "source_private.h"
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <limits.h>
+
+#include <jxl/decode.h>
+
+#define BACKEND_NB_CHANNELS       4
+#define BACKEND_DEFAULT_FRAMETIME 100
+#define BACKEND_NB_ALLOC_FRAMES   64
+
+struct jxl_frame {
+  void *data;
+  int frametime;
+};
+
+struct private {
+  void *data;
+  off_t data_len;
+  int owns_data;
+
+  int width;
+  int height;
+  int is_animation;
+
+  struct jxl_frame *frames;
+  int nb_allocd_frames;
+  int cur_frame;
+  int nb_frames;
+};
+
+static void free_private(void *raw_pvt)
+{
+  if (!raw_pvt)
+    return;
+
+  struct private *pvt = raw_pvt;
+
+  if (pvt->owns_data) {
+    if (pvt->data)
+      munmap(pvt->data, pvt->data_len);
+  }
+
+  if (pvt->frames) {
+    for (int i = 0; i != pvt->nb_allocd_frames; ++i)
+      if (pvt->frames[i].data)
+        free(pvt->frames[i].data);
+
+    free(pvt->frames);
+  }
+
+  free(pvt);
+}
+
+static void push_frame(struct private *pvt, struct imv_image **img, int 
*frametime)
+{
+  struct imv_bitmap *bmp = malloc(sizeof *bmp);
+  size_t sz = pvt->width * pvt->height * BACKEND_NB_CHANNELS;
+
+  bmp->width = pvt->width;
+  bmp->height = pvt->height;
+  bmp->format = IMV_ABGR;
+  bmp->data = malloc(sz);
+  memcpy(bmp->data, pvt->frames[pvt->cur_frame].data, sz);
+
+  *img = imv_image_create_from_bitmap(bmp);
+  *frametime = pvt->frames[pvt->cur_frame].frametime;
+}
+
+static void first_frame(void *raw_pvt, struct imv_image **img, int *frametime)
+{
+  *img = NULL;
+  *frametime = 0;
+
+  imv_log(IMV_DEBUG, "libjxl: first_frame called\n");
+
+  struct private *pvt = raw_pvt;
+  JxlDecoder *jxld = JxlDecoderCreate(NULL);
+  if (JxlDecoderSubscribeEvents(jxld, JXL_DEC_BASIC_INFO | JXL_DEC_FULL_IMAGE) 
!= JXL_DEC_SUCCESS) {
+    imv_log(IMV_ERROR, "libjxl: decoder failed to subscribe to events\n");
+    goto end;
+  }
+
+  JxlBasicInfo info;
+  JxlDecoderStatus sts = JxlDecoderSetInput(jxld, pvt->data, pvt->data_len);
+  if (sts != JXL_DEC_SUCCESS) {
+    imv_log(IMV_ERROR, "libjxl: decoder failed to set input\n");
+    goto end;
+  }
+  JxlDecoderCloseInput(jxld);
+
+  pvt->nb_frames = 0;
+  pvt->cur_frame = 0;
+
+  JxlPixelFormat fmt = { BACKEND_NB_CHANNELS, JXL_TYPE_UINT8, 
JXL_NATIVE_ENDIAN, 0 };
+  pvt->nb_allocd_frames = BACKEND_NB_ALLOC_FRAMES;
+  pvt->frames = calloc(pvt->nb_allocd_frames, sizeof *pvt->frames);
+  do {
+    sts = JxlDecoderProcessInput(jxld);
+
+    switch (sts) {
+      case JXL_DEC_SUCCESS:
+        break;
+      case JXL_DEC_ERROR:
+        imv_log(IMV_ERROR, "libjxl: decoder error\n");
+        goto end;
+      case JXL_DEC_NEED_MORE_INPUT:
+        imv_log(IMV_ERROR, "libjxl: decoder needs more input\n");
+        goto end;
+      case JXL_DEC_BASIC_INFO:
+        if (JxlDecoderGetBasicInfo(jxld, &info) != JXL_DEC_SUCCESS) {
+          imv_log(IMV_ERROR, "libjxl: decoder failed to get basic info\n");
+          goto end;
+        }
+        pvt->width = info.xsize;
+        pvt->height = info.ysize;
+        pvt->is_animation = info.have_animation == JXL_TRUE ? 1 : 0;
+        break;
+      case JXL_DEC_NEED_IMAGE_OUT_BUFFER:
+        {
+          size_t buf_sz;
+          if (JxlDecoderImageOutBufferSize(jxld, &fmt, &buf_sz) != 
JXL_DEC_SUCCESS) {
+            imv_log(IMV_ERROR, "libjxl: decoder failed to get output buffer 
size\n");
+            goto end;
+          }
+
+          if (pvt->nb_frames == pvt->nb_allocd_frames) {
+            pvt->frames = realloc(pvt->frames,
+                sizeof(struct jxl_frame) * (pvt->nb_allocd_frames + 
BACKEND_NB_ALLOC_FRAMES));
+            pvt->nb_allocd_frames += BACKEND_NB_ALLOC_FRAMES;
+            memset(&pvt->frames[pvt->nb_frames], 0,
+                (pvt->nb_allocd_frames * sizeof(struct jxl_frame)) - 
(pvt->nb_frames * sizeof(struct jxl_frame)));
+          }
+
+          struct jxl_frame *cur_frame = &pvt->frames[pvt->nb_frames];
+          cur_frame->data = malloc(buf_sz);
+
+          if (pvt->is_animation) {
+            if (info.animation.tps_numerator && info.animation.tps_denominator)
+              cur_frame->frametime = info.animation.tps_numerator / 
info.animation.tps_denominator;
+            else {
+                imv_log(IMV_DEBUG, "libjxl: no frametime info for animation, 
using default\n");
+                cur_frame->frametime = BACKEND_DEFAULT_FRAMETIME;
+            }
+          } else
+            cur_frame->frametime = 0;
+
+          if (JxlDecoderSetImageOutBuffer(jxld, &fmt, cur_frame->data, buf_sz) 
!= JXL_DEC_SUCCESS) {
+            imv_log(IMV_ERROR, "libjxl: JxlDecoderSetImageOutBuffer failed\n");
+            goto end;
+          }
+          break;
+        }
+      case JXL_DEC_FULL_IMAGE:
+        ++pvt->nb_frames;
+        continue;
+      default:
+        imv_log(IMV_ERROR, "libjxl: unknown decoder status\n");
+        goto end;
+    }
+  } while (sts != JXL_DEC_SUCCESS);
+
+  push_frame(pvt, img, frametime);
+
+end:
+  if (jxld)
+    JxlDecoderDestroy(jxld);
+}
+
+static void next_frame(void *raw_pvt, struct imv_image **img, int *frametime)
+{
+  *img = NULL;
+  *frametime = 0;
+
+  imv_log(IMV_DEBUG, "libjxl: next_frame called\n");
+
+  struct private *pvt = raw_pvt;
+
+  if (pvt->cur_frame == pvt->nb_frames - 1)
+    pvt->cur_frame = 0;
+  else
+    ++pvt->cur_frame;
+
+  push_frame(pvt, img, frametime);
+}
+
+static const struct imv_source_vtable vtable = {
+  .load_first_frame = first_frame,
+  .load_next_frame = next_frame,
+  .free = free_private,
+};
+
+static enum backend_result open_memory(void *data, size_t sz, struct 
imv_source **src)
+{
+  imv_log(IMV_DEBUG, "libjxl: open_memory called\n");
+
+  struct private *pvt = calloc(1, sizeof *pvt);
+
+  switch (JxlSignatureCheck(data, sz)) {
+    case JXL_SIG_NOT_ENOUGH_BYTES:
+      imv_log(IMV_DEBUG, "libjxl: not enough bytes to read\n");
+    case JXL_SIG_INVALID:
+      imv_log(IMV_DEBUG, "libjxl: valid jxl signature not found\n");
+      return BACKEND_UNSUPPORTED;
+    default:
+      pvt->owns_data = 0;
+      pvt->data = data;
+      pvt->data_len = sz;
+      break;
+    }
+
+  *src = imv_source_create(&vtable, pvt);
+
+  return BACKEND_SUCCESS;
+}
+
+static enum backend_result open_path(const char *path, struct imv_source **src)
+{
+  imv_log(IMV_DEBUG, "libjxl: open_path(%s)\n", path);
+
+  enum backend_result ret = BACKEND_SUCCESS;
+  struct private *pvt = calloc(1, sizeof *pvt);
+
+  int fd = open(path, O_RDONLY);
+  if (fd < 0) {
+    ret = BACKEND_BAD_PATH;
+    goto end;
+  }
+
+  pvt->data_len = lseek(fd, 0, SEEK_END);
+  if (pvt->data_len < 0) {
+    ret = BACKEND_BAD_PATH;
+    goto end;
+  }
+  pvt->data = mmap(NULL, pvt->data_len, PROT_READ, MAP_PRIVATE, fd, 0);
+  if (!pvt->data || pvt->data == MAP_FAILED) {
+    imv_log(IMV_ERROR, "libjxl: failed to map file into memory\n");
+    ret = BACKEND_BAD_PATH;
+    goto end;
+  }
+
+  switch (JxlSignatureCheck(pvt->data, pvt->data_len)) {
+    case JXL_SIG_NOT_ENOUGH_BYTES:
+      imv_log(IMV_DEBUG, "libjxl: not enough bytes to read\n");
+    case JXL_SIG_INVALID:
+      imv_log(IMV_DEBUG, "libjxl: valid jxl signature not found\n");
+      munmap(pvt->data, pvt->data_len);
+      ret = BACKEND_UNSUPPORTED;
+      goto end;
+    default:
+      pvt->owns_data = 1;
+      break;
+    }
+
+  *src = imv_source_create(&vtable, pvt);
+
+end:
+  if (fd >= 0)
+    close(fd);
+
+  return ret;
+}
+
+const struct imv_backend imv_backend_libjxl = {
+  .name = "libjxl",
+  .description = "The official JPEGXL reference implementation",
+  .website = "https://jpeg.org/jpegxl/";,
+  .license = "The Modified BSD License",
+  .open_path = &open_path,
+  .open_memory = &open_memory,
+};
+
+/* vim:set ts=2 sts=2 sw=2 et: */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/imv-v4.4.0/src/imv.c new/imv-v4.5.0/src/imv.c
--- old/imv-v4.4.0/src/imv.c    2023-01-18 23:20:52.000000000 +0100
+++ new/imv-v4.5.0/src/imv.c    2024-02-20 23:30:06.000000000 +0100
@@ -1,6 +1,7 @@
 #include "imv.h"
 
 #include <assert.h>
+#include <fcntl.h>
 #include <ctype.h>
 #include <errno.h>
 #include <getopt.h>
@@ -537,10 +538,6 @@
   imv->commands = imv_commands_create();
   imv->console = imv_console_create();
   imv_console_set_command_callback(imv->console, &command_callback, imv);
-  imv->ipc = imv_ipc_create();
-  if (imv->ipc) {
-    imv_ipc_set_command_callback(imv->ipc, &command_callback, imv);
-  }
   imv->title_text = strdup(
       "imv - [${imv_current_index}/${imv_file_count}]"
       " [${imv_width}x${imv_height}] [${imv_scale}%]"
@@ -754,6 +751,39 @@
   return true;
 }
 
+static void set_cloexec(int fd)
+{
+  int flags = fcntl(fd, F_GETFD);
+  assert(flags != -1);
+  flags |= FD_CLOEXEC;
+  int rc = fcntl(fd, F_SETFD, flags);
+  assert(rc != -1);
+}
+
+static bool parse_initial_width(struct imv *imv, const char *width_value)
+{
+  char *endptr;
+  errno = 0;
+  int val_x = strtol(width_value, &endptr, 10);
+  if(errno != 0 || *endptr != '\0' || endptr == width_value) {
+    return false;
+  }
+  imv->initial_width = val_x;
+  return true;
+}
+
+static bool parse_initial_height(struct imv *imv, const char *height_value)
+{
+  char *endptr;
+  errno = 0;
+  int val_y = strtol(height_value, &endptr, 10);
+  if(errno != 0 || *endptr != '\0' || endptr == height_value) {
+    return false;
+  }
+  imv->initial_height = val_y;
+  return true;
+}
+
 static void *pipe_stdin(void *data)
 {
   int *fd = data;
@@ -834,7 +864,7 @@
   int o;
 
  /* TODO getopt_long */
-  while ((o = getopt(argc, argv, "frdxhvlu:s:n:b:t:c:w:")) != -1) {
+  while ((o = getopt(argc, argv, "frdxhvlu:s:n:b:t:c:w:W:H:")) != -1) {
     switch(o) {
       case 'f': imv->start_fullscreen = true;                    break;
       case 'r': imv->recursive_load = true;                      break;
@@ -874,6 +904,18 @@
           return false;
         }
         break;
+      case 'W':
+        if(!parse_initial_width(imv, optarg)) {
+          imv_log(IMV_ERROR, "Invalid initial width value. Aborting.\n");
+          return false;
+        }
+        break;
+      case 'H':
+        if(!parse_initial_height(imv, optarg)) {
+          imv_log(IMV_ERROR, "Invalid initial height value. Aborting.\n");
+          return false;
+        }
+        break;
       case 'c': list_append(imv->startup_commands, optarg); break;
       case 'w': parse_window_title(imv, optarg); break;
       case '?':
@@ -927,6 +969,11 @@
   if (!setup_window(imv))
     return 1;
 
+  imv->ipc = imv_ipc_create();
+  if (imv->ipc) {
+    imv_ipc_set_command_callback(imv->ipc, &command_callback, imv);
+  }
+
   /* if loading paths from stdin, kick off a thread to do that - we'll receive
    * events back via internal events */
   int *stdin_pipe_fds = NULL;
@@ -942,6 +989,9 @@
       return 1;
     }
 
+    /* if a child process spawned by imv inherits the write part of the pipe,
+     * load_paths_from_stdin() will not exit until the child dies */
+    set_cloexec(stdin_pipe_fds[1]);
     imv->stdin_pipe = fdopen(stdin_pipe_fds[0], "re");
 
     if (pthread_create(&load_paths_thread, NULL, load_paths_from_stdin, imv)
@@ -1048,6 +1098,11 @@
               continue;
             }
 
+            if (!imv->stdin_image_data || !imv->stdin_image_data_len) {
+              /* Skip if image failed to load */
+              continue;
+            }
+
             result = backend->open_memory(imv->stdin_image_data,
                 imv->stdin_image_data_len, &new_source);
           } else {
@@ -2018,27 +2073,41 @@
   size_t len = 0;
   ssize_t r;
   size_t step = 4096; /* Arbitrary value of 4 KiB */
-  void *p;
+  void *new_buf;
 
-  errno = 0; /* clear errno */
+  errno = 0;
+  *buffer = NULL;
 
-  for (*buffer = NULL; (*buffer = realloc((p = *buffer), len + step));
-      len += (size_t)r) {
-    if ((r = read(STDIN_FILENO, (uint8_t *)*buffer + len, step)) == -1) {
-      perror(NULL);
+  while (1) {
+    new_buf = realloc(*buffer, len + step);
+    if (new_buf) {
+      *buffer = new_buf;
+    } else {
+      /* Failed to extend buffer */
+      int save = errno;
+      free(*buffer);
+      errno = save;
+      *buffer = NULL;
+      len = 0;
       break;
-    } else if (r == 0) {
+    }
+
+    r = read(STDIN_FILENO, (uint8_t *)*buffer + len, step);
+    if (r > 0) {
+      len += (size_t)r;
+    } else {
+      if (r < 0) {
+        /* Read error */
+        int save = errno;
+        perror(NULL);
+        free(*buffer);
+        errno = save;
+        len = 0;
+      }
       break;
     }
   }
 
-  /* realloc(3) leaves old buffer allocated in case of error */
-  if (*buffer == NULL && p != NULL) {
-    int save = errno;
-    free(p);
-    errno = save;
-    len = 0;
-  }
   return len;
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/imv-v4.4.0/src/main.c new/imv-v4.5.0/src/main.c
--- old/imv-v4.4.0/src/main.c   2023-01-18 23:20:52.000000000 +0100
+++ new/imv-v4.5.0/src/main.c   2024-02-20 23:30:06.000000000 +0100
@@ -9,6 +9,7 @@
 extern const struct imv_backend imv_backend_libjpeg;
 extern const struct imv_backend imv_backend_libnsgif;
 extern const struct imv_backend imv_backend_libheif;
+extern const struct imv_backend imv_backend_libjxl;
 
 int main(int argc, char **argv)
 {
@@ -46,6 +47,10 @@
   imv_install_backend(imv, &imv_backend_libheif);
 #endif
 
+#ifdef IMV_BACKEND_LIBJXL
+  imv_install_backend(imv, &imv_backend_libjxl);
+#endif
+
   if (!imv_load_config(imv)) {
     imv_free(imv);
     return 1;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/imv-v4.4.0/src/wl_window.c 
new/imv-v4.5.0/src/wl_window.c
--- old/imv-v4.4.0/src/wl_window.c      2023-01-18 23:20:52.000000000 +0100
+++ new/imv-v4.5.0/src/wl_window.c      2024-02-20 23:30:06.000000000 +0100
@@ -667,10 +667,12 @@
   .close = toplevel_close
 };
 
-static void connect_to_wayland(struct imv_window *window)
+static bool connect_to_wayland(struct imv_window *window)
 {
   window->wl_display = wl_display_connect(NULL);
-  assert(window->wl_display);
+  if (window->wl_display == NULL) {
+    return false;
+  }
   window->display_fd = wl_display_get_fd(window->wl_display);
   pipe(window->pipe_fds);
   set_nonblocking(window->pipe_fds[0]);
@@ -687,6 +689,8 @@
 
   window->egl_display = eglGetDisplay(window->wl_display);
   eglInitialize(window->egl_display, NULL, NULL);
+
+  return true;
 }
 
 static void create_window(struct imv_window *window, int width, int height,
@@ -789,7 +793,9 @@
   window->keyboard = imv_keyboard_create();
   assert(window->keyboard);
   window->wl_outputs = list_create();
-  connect_to_wayland(window);
+  if (!connect_to_wayland(window)) {
+    return NULL;
+  }
   create_window(window, width, height, title);
 
   struct sigevent timer_handler = {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/imv-v4.4.0/src/x11_window.c 
new/imv-v4.5.0/src/x11_window.c
--- old/imv-v4.4.0/src/x11_window.c     2023-01-18 23:20:52.000000000 +0100
+++ new/imv-v4.5.0/src/x11_window.c     2024-02-20 23:30:06.000000000 +0100
@@ -106,7 +106,9 @@
   set_nonblocking(window->pipe_fds[1]);
 
   window->x_display = XOpenDisplay(NULL);
-  assert(window->x_display);
+  if (window->x_display == NULL) {
+    return NULL;
+  }
   Window root = DefaultRootWindow(window->x_display);
   assert(root);
 
@@ -145,7 +147,7 @@
   window->wm_protocols = XInternAtom(window->x_display, "WM_PROTOCOLS", false);
   window->wm_delete_window = XInternAtom(window->x_display, 
"WM_DELETE_WINDOW", false);
   XSetWMProtocols(window->x_display, window->x_window, 
&window->wm_delete_window, 1);
-  XStoreName(window->x_display, window->x_window, title);
+  imv_window_set_title(window, title);
 
   window->x_glc = glXCreateContext(window->x_display, vi, NULL, GL_TRUE);
   assert(window->x_glc);
@@ -203,21 +205,28 @@
 
 void imv_window_set_title(struct imv_window *window, const char *title)
 {
+  Atom atom_wm_name;
+  Atom atom_utf8;
+
   XStoreName(window->x_display, window->x_window, title);
+  atom_wm_name = XInternAtom(window->x_display, "_NET_WM_NAME", False);
+  atom_utf8 = XInternAtom(window->x_display, "UTF8_STRING", False);
+  XChangeProperty(window->x_display, window->x_window, atom_wm_name, atom_utf8,
+      8, PropModeReplace, (unsigned char*)title, strlen(title));
 }
 
 bool imv_window_is_fullscreen(struct imv_window *window)
 {
-  size_t count = 0;
+  unsigned long count = 0;
   Atom type;
   int format;
-  size_t after;
+  unsigned long after;
   Atom *props = NULL;
   XGetWindowProperty(window->x_display, window->x_window, window->x_state,
       0, 1024, False, XA_ATOM, &type, &format, &count, &after, (unsigned 
char**)&props);
 
   bool fullscreen = false;
-  for (size_t i = 0; i < count; ++i) {
+  for (unsigned long i = 0; i < count; ++i) {
     if (props[i] == window->x_fullscreen) {
       fullscreen = true;
       break;

Reply via email to