Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package foot for openSUSE:Factory checked in 
at 2023-07-30 20:58:26
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/foot (Old)
 and      /work/SRC/openSUSE:Factory/.foot.new.32662 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "foot"

Sun Jul 30 20:58:26 2023 rev:25 rq:1101397 version:1.15.2

Changes:
--------
--- /work/SRC/openSUSE:Factory/foot/foot.changes        2023-07-24 
18:26:05.482194155 +0200
+++ /work/SRC/openSUSE:Factory/.foot.new.32662/foot.changes     2023-07-30 
20:58:34.087503316 +0200
@@ -1,0 +2,10 @@
+Sun Jul 30 17:16:33 UTC 2023 - Arnav Singh <opens...@arnavion.dev>
+
+- Update to v1.15.2:
+  * foot.ini options:
+    * Added tweak.bold-text-in-bright-amount option.
+  * Fixed various crashes related to copy-paste, font sizes, wayland support
+    of compositor, and more.
+  * See https://codeberg.org/dnkl/foot/releases/tag/1.15.2 for more details.
+
+-------------------------------------------------------------------

Old:
----
  foot-1.15.1.tar.gz

New:
----
  foot-1.15.2.tar.gz

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

Other differences:
------------------
++++++ foot.spec ++++++
--- /var/tmp/diff_new_pack.IRQENx/_old  2023-07-30 20:58:34.699506950 +0200
+++ /var/tmp/diff_new_pack.IRQENx/_new  2023-07-30 20:58:34.703506974 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           foot
-Version:        1.15.1
+Version:        1.15.2
 Release:        0
 Summary:        A Wayland terminal emulator
 License:        MIT
@@ -78,6 +78,7 @@
        -Dgrapheme-clustering=enabled \
        -Dime=true \
        -Dterminfo=enabled \
+       -Dterminfo-base-name=foot-extra \
        -Dtests=false \
        -Dthemes=true \
        -Dutmp-backend=libutempter \
@@ -87,8 +88,6 @@
 %install
 %meson_install
 rm -r %{buildroot}/%{_datadir}/doc/%{name}/
-mv %{buildroot}/%{_datadir}/terminfo/f/foot 
%{buildroot}/%{_datadir}/terminfo/f/foot-extra
-mv %{buildroot}/%{_datadir}/terminfo/f/foot-direct 
%{buildroot}/%{_datadir}/terminfo/f/foot-extra-direct
 
 %files
 %license LICENSE

++++++ foot-1.15.1.tar.gz -> foot-1.15.2.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/foot/.builds/alpine-x64.yml 
new/foot/.builds/alpine-x64.yml
--- old/foot/.builds/alpine-x64.yml     2023-07-21 08:57:03.000000000 +0200
+++ new/foot/.builds/alpine-x64.yml     2023-07-30 13:18:55.000000000 +0200
@@ -47,6 +47,9 @@
       ninja -C bld/release -k0
       meson test -C bld/release --print-errorlogs
   - codespell: |
+      python3 -m venv codespell-venv
+      source codespell-venv/bin/activate
       pip install codespell
       cd foot
       ~/.local/bin/codespell -Lser,doas,zar README.md INSTALL.md CHANGELOG.md 
*.c *.h doc/*.scd
+      deactivate
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/foot/.woodpecker.yml new/foot/.woodpecker.yml
--- old/foot/.woodpecker.yml    2023-07-21 08:57:03.000000000 +0200
+++ new/foot/.woodpecker.yml    2023-07-30 13:18:55.000000000 +0200
@@ -8,8 +8,11 @@
     commands:
       - apk add python3
       - apk add py3-pip
+      - python3 -m venv codespell-venv
+      - source codespell-venv/bin/activate
       - pip install codespell
       - codespell -Lser,doas,zar README.md INSTALL.md CHANGELOG.md *.c *.h 
doc/*.scd
+      - deactivate
 
   subprojects:
     when:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/foot/CHANGELOG.md new/foot/CHANGELOG.md
--- old/foot/CHANGELOG.md       2023-07-21 08:57:03.000000000 +0200
+++ new/foot/CHANGELOG.md       2023-07-30 13:18:55.000000000 +0200
@@ -1,5 +1,6 @@
 # Changelog
 
+* [1.15.2](#1-15-2)
 * [1.15.1](#1-15-1)
 * [1.15.0](#1-15-0)
 * [1.14.0](#1-14-0)
@@ -43,6 +44,44 @@
 * [1.2.0](#1-2-0)
 
 
+## 1.15.2
+
+### Added
+
+* `[tweak].bold-text-in-bright-amount` option ([#1434][1434]).
+* `-Dterminfo-base-name` meson option, allowing you to name the
+  terminfo files to something other than `-Ddefault-terminfo`. Use
+  case: have foot default to using the terminfo from ncurses (`foot`,
+  `foot-direct`), while still packaging foot's terminfo files, but
+  under a different name (e.g. `foot-extra`, `foot-extra-direct`).
+
+[1434]: https://codeberg.org/dnkl/foot/issues/1434
+
+
+### Fixed
+
+* Crash when copying text that contains invalid UTF-8 ([#1423][1423]).
+* Wrong font size after suspending the monitor ([#1431][1431]).
+* Vertical alignment in URL jump labels, and the scrollback position
+  indicator ([#1430][1430]).
+* Regression: line- and box drawing characters not covering the full
+  height of the line, when a custom `line-height` is being used
+  ([#1430][1430]).
+* Crash when compositor does not implement the _viewporter_ interface
+  ([#1444][1444]).
+* CSD rendering with fractional scaling ([#1441][1441]).
+* Regression: crash with certain combinations of
+  `--window-size-chars=NxM` and desktop scaling factors
+  ([#1446][1446]).
+
+[1423]: https://codeberg.org/dnkl/foot/issues/1423
+[1431]: https://codeberg.org/dnkl/foot/issues/1431
+[1430]: https://codeberg.org/dnkl/foot/issues/1430
+[1444]: https://codeberg.org/dnkl/foot/issues/1444
+[1441]: https://codeberg.org/dnkl/foot/issues/1441
+[1446]: https://codeberg.org/dnkl/foot/issues/1446
+
+
 ## 1.15.1
 
 ### Changed
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/foot/INSTALL.md new/foot/INSTALL.md
--- old/foot/INSTALL.md 2023-07-21 08:57:03.000000000 +0200
+++ new/foot/INSTALL.md 2023-07-30 13:18:55.000000000 +0200
@@ -151,6 +151,7 @@
 | `-Dgrapheme-clustering`              | feature | `auto`                  | 
Enables grapheme clustering                                                     
| libutf8proc         |
 | `-Dterminfo`                         | feature | `enabled`               | 
Build and install terminfo files                                                
| tic (ncurses)       |
 | `-Ddefault-terminfo`                 | string  | `foot`                  | 
Default value of `TERM`                                                         
| None                |
+| `-Dterminfo-base-name`               | string  | `-Ddefault-terminfo`    | 
Base name of the generated terminfo files                                       
| None                |
 | `-Dcustom-terminfo-install-location` | string  | `${datadir}/terminfo`   | 
Value to set `TERMINFO` to                                                      
| None                |
 | `-Dsystemd-units-dir`                | string  | `${systemduserunitdir}` | 
Where to install the systemd service files (absolute)                           
| None                |
 | `-Dutmp-backend`                     | combo   | `auto`                  | 
Which utmp backend to use (`none`, `libutempter`, `ulog` or `auto`)             
| libutempter or ulog |
@@ -165,8 +166,18 @@
 `$TERM`, and the names of the terminfo files (if
 `-Dterminfo=enabled`).
 
-`-Dcustom-terminfo-install-location` enables foot’s terminfo to
-co-exist with ncurses’ version, without changing the terminfo
+If you want foot to use the terminfo files from ncurses, but still
+package foot's own terminfo files under a different name, you can use
+the `-Dterminfo-base-name` option. Many distributions use the name
+`foot-extra`, and thus it might be a good idea to re-use that:
+
+```sh
+meson ... -Ddefault-terminfo=foot -Dterminfo-base-name=foot-extra
+```
+(or just leave out `-Ddefault-terminfo`, since it defaults to `foot` anyway).
+
+Finally, `-Dcustom-terminfo-install-location` enables foot’s terminfo
+to co-exist with ncurses’ version, without changing the terminfo
 names. The idea is that you install foot’s terminfo to a non-standard
 location, for example `/usr/share/foot/terminfo`. Use
 `-Dcustom-terminfo-install-location` to tell foot where the terminfo
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/foot/box-drawing.c new/foot/box-drawing.c
--- old/foot/box-drawing.c      2023-07-21 08:57:03.000000000 +0200
+++ new/foot/box-drawing.c      2023-07-30 13:18:55.000000000 +0200
@@ -3011,7 +3011,7 @@
         .cols = 1,
         .pix = buf.pix,
         .x = -term->font_x_ofs,
-        .y = term->font_y_ofs + term->fonts[0]->ascent,
+        .y = term_font_baseline(term),
         .width = width,
         .height = height,
         .advance = {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/foot/config.c new/foot/config.c
--- old/foot/config.c   2023-07-21 08:57:03.000000000 +0200
+++ new/foot/config.c   2023-07-30 13:18:55.000000000 +0200
@@ -480,7 +480,7 @@
 }
 
 static bool NOINLINE
-value_to_double(struct context *ctx, float *res)
+value_to_float(struct context *ctx, float *res)
 {
     const char *s = ctx->value;
 
@@ -659,7 +659,7 @@
         res->px = value;
     } else {
         float value;
-        if (!value_to_double(ctx, &value))
+        if (!value_to_float(ctx, &value))
             return false;
         res->pt = value;
         res->px = 0;
@@ -1089,7 +1089,7 @@
     }
 
     else if (strcmp(key, "multiplier") == 0)
-        return value_to_double(ctx, &conf->scrollback.multiplier);
+        return value_to_float(ctx, &conf->scrollback.multiplier);
 
     else {
         LOG_CONTEXTUAL_ERR("not a valid option: %s", key);
@@ -1298,7 +1298,7 @@
 
     else if (strcmp(key, "alpha") == 0) {
         float alpha;
-        if (!value_to_double(ctx, &alpha))
+        if (!value_to_float(ctx, &alpha))
             return false;
 
         if (alpha < 0. || alpha > 1.) {
@@ -2461,7 +2461,7 @@
     }
 
     else if (strcmp(key, "box-drawing-base-thickness") == 0)
-        return value_to_double(ctx, &conf->tweak.box_drawing_base_thickness);
+        return value_to_float(ctx, &conf->tweak.box_drawing_base_thickness);
 
     else if (strcmp(key, "box-drawing-solid-shades") == 0)
         return value_to_bool(ctx, &conf->tweak.box_drawing_solid_shades);
@@ -2472,6 +2472,9 @@
     else if (strcmp(key, "sixel") == 0)
         return value_to_bool(ctx, &conf->tweak.sixel);
 
+    else if (strcmp(key, "bold-text-in-bright-amount") == 0)
+        return value_to_float(ctx, &conf->bold_in_bright.amount);
+
     else {
         LOG_CONTEXTUAL_ERR("not a valid option: %s", key);
         return false;
@@ -2939,6 +2942,7 @@
         .bold_in_bright = {
             .enabled = false,
             .palette_based = false,
+            .amount = 1.3,
         },
         .startup_mode = STARTUP_WINDOWED,
         .fonts = {{0}},
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/foot/config.h new/foot/config.h
--- old/foot/config.h   2023-07-21 08:57:03.000000000 +0200
+++ new/foot/config.h   2023-07-30 13:18:55.000000000 +0200
@@ -133,6 +133,7 @@
     struct {
         bool enabled;
         bool palette_based;
+        float amount;
     } bold_in_bright;
 
     enum { STARTUP_WINDOWED, STARTUP_MAXIMIZED, STARTUP_FULLSCREEN } 
startup_mode;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/foot/csi.c new/foot/csi.c
--- old/foot/csi.c      2023-07-21 08:57:03.000000000 +0200
+++ new/foot/csi.c      2023-07-30 13:18:55.000000000 +0200
@@ -1208,8 +1208,8 @@
                     char reply[64];
                     size_t n = xsnprintf(
                         reply, sizeof(reply), "\033[4;%d;%dt",
-                        (int)round(height / term->scale),
-                        (int)(width / term->scale));
+                        (int)roundf(height / term->scale),
+                        (int)roundf((width / term->scale)));
                     term_to_slave(term, reply, n);
                 }
                 break;
@@ -1233,8 +1233,8 @@
                 char reply[64];
                 size_t n = xsnprintf(
                     reply, sizeof(reply), "\033[6;%d;%dt",
-                    (int)round(term->cell_height / term->scale),
-                    (int)round(term->cell_width / term->scale));
+                    (int)roundf(term->cell_height / term->scale),
+                    (int)roundf(term->cell_width / term->scale));
                 term_to_slave(term, reply, n);
                 break;
             }
@@ -1252,8 +1252,8 @@
                     char reply[64];
                     size_t n = xsnprintf(
                         reply, sizeof(reply), "\033[9;%d;%dt",
-                        (int)round(it->item->dim.px_real.height / 
term->cell_height / term->scale),
-                        (int)round(it->item->dim.px_real.width / 
term->cell_width / term->scale));
+                        (int)roundf(it->item->dim.px_real.height / 
term->cell_height / term->scale),
+                        (int)roundf(it->item->dim.px_real.width / 
term->cell_width / term->scale));
                     term_to_slave(term, reply, n);
                     break;
                 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/foot/doc/foot.ini.5.scd new/foot/doc/foot.ini.5.scd
--- old/foot/doc/foot.ini.5.scd 2023-07-21 08:57:03.000000000 +0200
+++ new/foot/doc/foot.ini.5.scd 2023-07-30 13:18:55.000000000 +0200
@@ -1337,7 +1337,13 @@
        Default: _512_. Maximum allowed: _2048_ (2GB).
 
 *sixel*
-       Boolean. When enabled, foot will process sixel images. Default: _yes_
+       Boolean. When enabled, foot will process sixel images. Default:
+       _yes_
+
+*bold-text-in-bright-amount*
+       Amount by which bold fonts are brightened when
+       *bold-text-in-bright* is set to *yes* (the *palette-based* variant
+       is not affected by this option). Default: _1.3_.
 
 # SEE ALSO
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/foot/hsl.c new/foot/hsl.c
--- old/foot/hsl.c      2023-07-21 08:57:03.000000000 +0200
+++ new/foot/hsl.c      2023-07-30 13:18:55.000000000 +0200
@@ -83,7 +83,7 @@
     b += m;
 
     return (
-        (int)round(r * 255.) << 16 |
-        (int)round(g * 255.) << 8 |
-        (int)round(b * 255.) << 0);
+        (uint8_t)round(r * 255.) << 16 |
+        (uint8_t)round(g * 255.) << 8 |
+        (uint8_t)round(b * 255.) << 0);
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/foot/meson.build new/foot/meson.build
--- old/foot/meson.build        2023-07-21 08:57:03.000000000 +0200
+++ new/foot/meson.build        2023-07-30 13:18:55.000000000 +0200
@@ -1,5 +1,5 @@
 project('foot', 'c',
-        version: '1.15.1',
+        version: '1.15.2',
         license: 'MIT',
         meson_version: '>=0.59.0',
         default_options: [
@@ -352,11 +352,16 @@
   install_subdir('themes', install_dir: join_paths(get_option('datadir'), 
'foot'))
 endif
 
+terminfo_base_name = get_option('terminfo-base-name')
+if terminfo_base_name == ''
+  terminfo_base_name = get_option('default-terminfo')
+endif
+
 tic = find_program('tic', native: true, required: get_option('terminfo'))
 if tic.found()
   conf_data = configuration_data(
     {
-      'default_terminfo': get_option('default-terminfo'),
+      'default_terminfo': terminfo_base_name
     }
   )
 
@@ -367,9 +372,9 @@
   )
   custom_target(
     'terminfo',
-    output: get_option('default-terminfo')[0],
+    output: terminfo_base_name[0],
     input: preprocessed,
-    command: [tic, '-x', '-o', '@OUTDIR@', '-e', 
'@0@,@0@-direct'.format(get_option('default-terminfo')), '@INPUT@'],
+    command: [tic, '-x', '-o', '@OUTDIR@', '-e', 
'@0@,@0@-direct'.format(terminfo_base_name), '@INPUT@'],
     install: true,
     install_dir: terminfo_install_location
   )
@@ -395,6 +400,7 @@
     'utmp backend': utmp_backend,
     'utmp helper default path': utmp_default_helper_path,
     'Build terminfo': tic.found(),
+    'Terminfo base name': terminfo_base_name,
     'Terminfo install location': terminfo_install_location,
     'Default TERM': get_option('default-terminfo'),
     'Set TERMINFO': get_option('custom-terminfo-install-location') != '',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/foot/meson_options.txt new/foot/meson_options.txt
--- old/foot/meson_options.txt  2023-07-21 08:57:03.000000000 +0200
+++ new/foot/meson_options.txt  2023-07-30 13:18:55.000000000 +0200
@@ -15,7 +15,8 @@
 option('terminfo', type: 'feature', value: 'enabled', description: 'Build and 
install foot\'s terminfo files.')
 option('default-terminfo', type: 'string', value: 'foot',
        description: 'Default value of the "term" option in foot.ini.')
-
+option('terminfo-base-name', type: 'string',
+       description: 'Base name of the generated terminfo files. Defaults to 
the value of the \'default-terminfo\' meson option')
 option('custom-terminfo-install-location', type: 'string', value: '',
        description: 'Path to foot\'s terminfo, relative to ${prefix}. If set, 
foot will set $TERMINFO to this value in the client process.')
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/foot/render.c new/foot/render.c
--- old/foot/render.c   2023-07-21 08:57:03.000000000 +0200
+++ new/foot/render.c   2023-07-30 13:18:55.000000000 +0200
@@ -299,25 +299,16 @@
 
     int hue, sat, lum;
     rgb_to_hsl(color, &hue, &sat, &lum);
-    return hsl_to_rgb(hue, sat, min(100, lum * 1.3));
-}
-
-static inline int
-font_baseline(const struct terminal *term)
-{
-    const struct fcft_font *font = term->fonts[0];
-    const int line_height = term->cell_height;
-    const int font_height = font->ascent + font->descent;
-    const int glyph_top_y = round((line_height - font_height) / 2.);
 
-    return term->font_y_ofs + glyph_top_y + font->ascent;
+    lum = (int)roundf(lum * term->conf->bold_in_bright.amount);
+    return hsl_to_rgb(hue, sat, min(lum, 100));
 }
 
 static void
 draw_unfocused_block(const struct terminal *term, pixman_image_t *pix,
                      const pixman_color_t *color, int x, int y, int cell_cols)
 {
-    const int scale = round(term->scale);
+    const int scale = (int)roundf(term->scale);
     const int width = min(min(scale, term->cell_width), term->cell_height);
 
     pixman_image_fill_rectangles(
@@ -335,7 +326,7 @@
                  const struct fcft_font *font,
                  const pixman_color_t *color, int x, int y)
 {
-    int baseline = y + font_baseline(term) - term->fonts[0]->ascent;
+    int baseline = y + term_font_baseline(term) - term->fonts[0]->ascent;
     pixman_image_fill_rectangles(
         PIXMAN_OP_SRC, pix, color,
         1, &(pixman_rectangle16_t){
@@ -347,7 +338,7 @@
 static int
 underline_offset(const struct terminal *term, const struct fcft_font *font)
 {
-    return font_baseline(term) -
+    return term_font_baseline(term) -
         (term->conf->use_custom_underline_offset
          ? -term_pt_or_px_as_pixels(term, &term->conf->underline_offset)
          : font->underline.position);
@@ -401,7 +392,7 @@
     pixman_image_fill_rectangles(
         PIXMAN_OP_SRC, pix, color,
         1, &(pixman_rectangle16_t){
-            x, y + font_baseline(term) - font->strikeout.position,
+            x, y + term_font_baseline(term) - font->strikeout.position,
             cols * term->cell_width, font->strikeout.thickness});
 }
 
@@ -767,13 +758,13 @@
             if (!(cell->attrs.blink && term->blink.state == BLINK_OFF)) {
                 pixman_image_composite32(
                     PIXMAN_OP_OVER, glyph->pix, NULL, pix, 0, 0, 0, 0,
-                    pen_x + letter_x_ofs + g_x, y + font_baseline(term) - g_y,
+                    pen_x + letter_x_ofs + g_x, y + term_font_baseline(term) - 
g_y,
                     glyph->width, glyph->height);
             }
         } else {
             pixman_image_composite32(
                 PIXMAN_OP_OVER, clr_pix, glyph->pix, pix, 0, 0, 0, 0,
-                pen_x + letter_x_ofs + g_x, y + font_baseline(term) - g_y,
+                pen_x + letter_x_ofs + g_x, y + term_font_baseline(term) - g_y,
                 glyph->width, glyph->height);
 
             /* Combining characters */
@@ -813,7 +804,7 @@
                         /* Some fonts use a negative offset, while others use a
                          * "normal" offset */
                         pen_x + x_ofs + g->x,
-                        y + font_baseline(term) - g->y,
+                        y + term_font_baseline(term) - g->y,
                         g->width, g->height);
                 }
             }
@@ -1817,33 +1808,49 @@
     const bool borders_visible = wayl_win_csd_borders_visible(term->window);
     const bool title_visible = wayl_win_csd_titlebar_visible(term->window);
 
-    /* Only title bar is rendered in maximized mode */
+    const float scale = term->scale;
+
     const int border_width = borders_visible
-        ? term->conf->csd.border_width * term->scale : 0;
+        ? roundf(term->conf->csd.border_width * scale) : 0;
 
     const int title_height = title_visible
-        ? term->conf->csd.title_height * term->scale : 0;
+        ? roundf(term->conf->csd.title_height * scale) : 0;
 
     const int button_width = title_visible
-        ? term->conf->csd.button_width * term->scale : 0;
+        ? roundf(term->conf->csd.button_width * scale) : 0;
 
     const int button_close_width = term->width >= 1 * button_width
         ? button_width : 0;
 
     const int button_maximize_width =
         term->width >= 2 * button_width && 
term->window->wm_capabilities.maximize
-        ? button_width : 0;
+            ? button_width : 0;
 
     const int button_minimize_width =
         term->width >= 3 * button_width && 
term->window->wm_capabilities.minimize
-        ? button_width : 0;
+            ? button_width : 0;
+
+    /*
+     * With fractional scaling, we must ensure the offset, when
+     * divided by the scale (in set_position()), and the scaled back
+     * (by the compositor), matches the actual pixel count made up by
+     * the titlebar and the border.
+     */
+    const int top_offset = roundf(
+        scale * (roundf(-title_height / scale) - roundf(border_width / 
scale)));
+
+    const int top_bottom_width = roundf(
+        scale * (roundf(term->width / scale) + 2 * roundf(border_width / 
scale)));
+
+    const int left_right_height = roundf(
+        scale * (roundf(title_height / scale) + roundf(term->height / scale)));
 
     switch (surf_idx) {
-    case CSD_SURF_TITLE:  return (struct csd_data){            0,              
  -title_height,                   term->width,                 title_height};
-    case CSD_SURF_LEFT:   return (struct csd_data){-border_width,              
  -title_height,                   border_width, title_height + term->height};
-    case CSD_SURF_RIGHT:  return (struct csd_data){  term->width,              
  -title_height,                   border_width, title_height + term->height};
-    case CSD_SURF_TOP:    return (struct csd_data){-border_width, 
-title_height - border_width, term->width + 2 * border_width,                
border_width};
-    case CSD_SURF_BOTTOM: return (struct csd_data){-border_width,              
   term->height, term->width + 2 * border_width,                border_width};
+    case CSD_SURF_TITLE:  return (struct csd_data){            0, 
-title_height,      term->width,      title_height};
+    case CSD_SURF_LEFT:   return (struct csd_data){-border_width, 
-title_height,     border_width, left_right_height};
+    case CSD_SURF_RIGHT:  return (struct csd_data){  term->width, 
-title_height,     border_width, left_right_height};
+    case CSD_SURF_TOP:    return (struct csd_data){-border_width,    
top_offset, top_bottom_width,      border_width};
+    case CSD_SURF_BOTTOM: return (struct csd_data){-border_width,  
term->height, top_bottom_width,      border_width};
 
     /* Positioned relative to CSD_SURF_TITLE */
     case CSD_SURF_MINIMIZE: return (struct csd_data){term->width - 3 * 
button_width, 0, button_minimize_width, title_height};
@@ -1937,12 +1944,12 @@
         if (pixman_image_get_format(glyph->pix) == PIXMAN_a8r8g8b8) {
             pixman_image_composite32(
                 PIXMAN_OP_OVER, glyph->pix, NULL, buf->pix[0], 0, 0, 0, 0,
-                x + x_ofs + glyph->x, y + term->font_y_ofs + font->ascent - 
glyph->y,
+                x + x_ofs + glyph->x, y + term->font_y_ofs + font->ascent 
/*term_font_baseline(term)*/ - glyph->y,
                 glyph->width, glyph->height);
         } else {
             pixman_image_composite32(
                 PIXMAN_OP_OVER, src, glyph->pix, buf->pix[0], 0, 0, 0, 0,
-                x + x_ofs + glyph->x, y + term->font_y_ofs + font->ascent - 
glyph->y,
+                x + x_ofs + glyph->x, y + term->font_y_ofs + font->ascent /* 
term_font_baseline(term)*/ - glyph->y,
                 glyph->width, glyph->height);
         }
 
@@ -2033,8 +2040,8 @@
      */
 
     float scale = term->scale;
-    int bwidth = round(term->conf->csd.border_width * scale);
-    int vwidth = round(term->conf->csd.border_width_visible * scale); /* 
Visible size */
+    int bwidth = (int)roundf(term->conf->csd.border_width * scale);
+    int vwidth = (int)roundf(term->conf->csd.border_width_visible * scale); /* 
Visible size */
 
     xassert(bwidth >= vwidth);
 
@@ -2379,6 +2386,7 @@
     if (term->window->is_fullscreen)
         return;
 
+    const float scale = term->scale;
     struct csd_data infos[CSD_SURF_COUNT];
     int widths[CSD_SURF_COUNT];
     int heights[CSD_SURF_COUNT];
@@ -2406,8 +2414,7 @@
 
         widths[i] = width;
         heights[i] = height;
-
-        wl_subsurface_set_position(sub, x / term->scale, y / term->scale);
+        wl_subsurface_set_position(sub, roundf(x / scale), roundf(y / scale));
     }
 
     struct buffer *bufs[CSD_SURF_COUNT];
@@ -2498,7 +2505,7 @@
         char lineno_str[64];
         snprintf(lineno_str, sizeof(lineno_str), "%d", rebased_view + 1);
         mbstoc32(_text, lineno_str, ALEN(_text));
-        cell_count = ceil(log10(term->grid->num_rows));
+        cell_count = (int)ceilf(log10f(term->grid->num_rows));
         break;
     }
 
@@ -2508,13 +2515,14 @@
         break;
     }
 
-    const int scale = term->scale;
-    const int margin = 3 * scale;
+    const float scale = term->scale;
+    const int margin = (int)roundf(3. * scale);
+
+    int width = margin + cell_count * term->cell_width + margin;
+    int height = margin + term->cell_height + margin;
 
-    const int width =
-        (2 * margin + cell_count * term->cell_width + scale - 1) / scale * 
scale;
-    const int height =
-        (2 * margin + term->cell_height + scale - 1) / scale * scale;
+    width = roundf(scale * ceilf(width / scale));
+    height = roundf(scale * ceilf(height / scale));
 
     /* *Where* to render - parent relative coordinates */
     int surf_top = 0;
@@ -2542,8 +2550,11 @@
     }
     }
 
-    const int x = (term->width - margin - width) / scale * scale;
-    const int y = (term->margins.top + surf_top) / scale * scale;
+    int x = term->width - margin - width;
+    int y = term->margins.top + surf_top;
+
+    x = roundf(scale * ceilf(x / scale));
+    y = roundf(scale * ceilf(y / scale));
 
     if (y + height > term->height) {
         wl_surface_attach(win->scrollback_indicator.surface.surf, NULL, 0, 0);
@@ -2555,7 +2566,7 @@
     struct buffer *buf = shm_get_buffer(chain, width, height);
 
     wl_subsurface_set_position(
-        win->scrollback_indicator.sub, x / scale, y / scale);
+        win->scrollback_indicator.sub, roundf(x / scale), roundf(y / scale));
 
     uint32_t fg = term->colors.table[0];
     uint32_t bg = term->colors.table[8 + 4];
@@ -2584,21 +2595,23 @@
     char32_t text[256];
     mbstoc32(text, usecs_str, ALEN(text));
 
-    const int scale = round(term->scale);
+    const float scale = term->scale;
     const int cell_count = c32len(text);
-    const int margin = 3 * scale;
-    const int width =
-        (2 * margin + cell_count * term->cell_width + scale - 1) / scale * 
scale;
-    const int height =
-        (2 * margin + term->cell_height + scale - 1) / scale * scale;
+    const int margin = (int)roundf(3. * scale);
+
+    int width = margin + cell_count * term->cell_width + margin;
+    int height = margin + term->cell_height + margin;
+
+    width = roundf(scale * ceilf(width / scale));
+    height = roundf(scale * ceilf(height / scale));
 
     struct buffer_chain *chain = term->render.chains.render_timer;
     struct buffer *buf = shm_get_buffer(chain, width, height);
 
     wl_subsurface_set_position(
         win->render_timer.sub,
-        margin / term->scale,
-        (term->margins.top + term->cell_height - margin) / term->scale);
+        roundf(margin / scale),
+        roundf((term->margins.top + term->cell_height - margin) / scale));
 
     render_osd(
         term,
@@ -3143,18 +3156,21 @@
     const size_t total_cells = c32swidth(text, text_len);
     const size_t wanted_visible_cells = max(20, total_cells);
 
-    xassert(term->scale >= 1);
-    const int rounded_scale = round(term->scale);
+    const float scale = term->scale;
+    xassert(scale >= 1.);
+    const size_t margin = (size_t)roundf(3 * scale);
+
+    size_t width = term->width - 2 * margin;
+    size_t height = min(
+        term->height - 2 * margin,
+        margin + 1 * term->cell_height + margin);
 
-    const size_t margin = 3 * rounded_scale;
+    width = roundf(scale * ceilf((term->width - 2 * margin) / scale));
+    height = roundf(scale * ceilf(height / scale));
 
-    const size_t width = term->width - 2 * margin;
-    const size_t visible_width = min(
+    size_t visible_width = min(
         term->width - 2 * margin,
-        (2 * margin + wanted_visible_cells * term->cell_width + rounded_scale 
- 1) / rounded_scale * rounded_scale);
-    const size_t height = min(
-        term->height - 2 * margin,
-        (2 * margin + 1 * term->cell_height + rounded_scale - 1) / 
rounded_scale * rounded_scale);
+        margin + wanted_visible_cells * term->cell_width + margin);
 
     const size_t visible_cells = (visible_width - 2 * margin) / 
term->cell_width;
     size_t glyph_offset = term->render.search_glyph_offset;
@@ -3364,7 +3380,7 @@
             /* Glyph surface is a pre-rendered image (typically a color 
emoji...) */
             pixman_image_composite32(
                 PIXMAN_OP_OVER, glyph->pix, NULL, buf->pix[0], 0, 0, 0, 0,
-                x + x_ofs + glyph->x, y + font_baseline(term) - glyph->y,
+                x + x_ofs + glyph->x, y + term_font_baseline(term) - glyph->y,
                 glyph->width, glyph->height);
         } else {
             int combining_ofs = width == 0
@@ -3376,7 +3392,7 @@
             pixman_image_composite32(
                 PIXMAN_OP_OVER, src, glyph->pix, buf->pix[0], 0, 0, 0, 0,
                 x + x_ofs + combining_ofs + glyph->x,
-                y + font_baseline(term) - glyph->y,
+                y + term_font_baseline(term) - glyph->y,
             glyph->width, glyph->height);
             pixman_image_unref(src);
         }
@@ -3401,10 +3417,10 @@
     /* TODO: this is only necessary on a window resize */
     wl_subsurface_set_position(
         term->window->search.sub,
-        margin / term->scale,
-        max(0, (int32_t)term->height - height - margin) / term->scale);
+        roundf(margin / scale),
+        roundf(max(0, (int32_t)term->height - height - margin) / scale));
 
-    wayl_surface_scale(term->window, &term->window->search.surface, buf, 
term->scale);
+    wayl_surface_scale(term->window, &term->window->search.surface, buf, 
scale);
     wl_surface_attach(term->window->search.surface.surf, buf->wl_buf, 0, 0);
     wl_surface_damage_buffer(term->window->search.surface.surf, 0, 0, width, 
height);
 
@@ -3431,9 +3447,9 @@
     struct wl_window *win = term->window;
     xassert(tll_length(win->urls) > 0);
 
-    const int scale = round(term->scale);
-    const int x_margin = 2 * scale;
-    const int y_margin = 1 * scale;
+    const float scale = term->scale;
+    const int x_margin = (int)roundf(2 * scale);
+    const int y_margin = (int)roundf(1 * scale);
 
     /* Calculate view start, counted from the *current* scrollback start */
     const int scrollback_end
@@ -3603,10 +3619,11 @@
         if (cols == 0)
             continue;
 
-        const int width =
-            (2 * x_margin + cols * term->cell_width + scale - 1) / scale * 
scale;
-        const int height =
-            (2 * y_margin + term->cell_height + scale - 1) / scale * scale;
+        int width = x_margin + cols * term->cell_width + x_margin;
+        int height = y_margin + term->cell_height + y_margin;
+
+        width = roundf(scale * ceilf(width / scale));
+        height = roundf(scale * ceilf(height / scale));
 
         info[render_count].url = &it->item;
         info[render_count].text = xc32dup(label);
@@ -3642,8 +3659,8 @@
 
         wl_subsurface_set_position(
             sub_surf->sub,
-            (term->margins.left + x) / term->scale,
-            (term->margins.top + y) / term->scale);
+            roundf((term->margins.left + x) / scale),
+            roundf((term->margins.top + y) / scale));
 
         render_osd(
             term, sub_surf, term->fonts[0], bufs[i], label,
@@ -3916,22 +3933,9 @@
                 width += 2 * term->conf->pad_x * scale;
                 height += 2 * term->conf->pad_y * scale;
 
-                /*
-                 * Ensure we can scale to logical size, and back to
-                 * pixels without truncating.
-                 */
-                if (wayl_fractional_scaling(term->wl)) {
-                    xassert((int)round(scale) == (int)scale);
-
-                    int iscale = scale;
-                    if (width % iscale)
-                        width += iscale - width % iscale;
-                    if (height % iscale)
-                        height += iscale - height % iscale;
-
-                    xassert(width % iscale == 0);
-                    xassert(height % iscale == 0);
-                }
+                /* Ensure width/height is a valid multiple of scale */
+                width = roundf(scale * roundf(width / scale));
+                height = roundf(scale * roundf(height / scale));
                 break;
             }
         }
@@ -3942,8 +3946,8 @@
     const int min_rows = 1;
 
     /* Minimum window size (must be divisible by the scaling factor)*/
-    const int min_width = (min_cols * term->cell_width + scale - 1) / scale * 
scale;
-    const int min_height = (min_rows * term->cell_height + scale - 1) / scale 
* scale;
+    const int min_width = roundf(scale * ceilf((min_cols * term->cell_width) / 
scale));
+    const int min_height = roundf(scale * ceilf((min_rows * term->cell_height) 
/ scale));
 
     width = max(width, min_width);
     height = max(height, min_height);
@@ -4203,22 +4207,43 @@
         const bool title_shown = wayl_win_csd_titlebar_visible(term->window);
         const bool border_shown = wayl_win_csd_borders_visible(term->window);
 
-        const int title_height =
-            title_shown ? term->conf->csd.title_height : 0;
-        const int border_width =
-            border_shown ? term->conf->csd.border_width_visible : 0;
+        const int title = title_shown
+            ? roundf(term->conf->csd.title_height * scale)
+            : 0;
+        const int border = border_shown
+            ? roundf(term->conf->csd.border_width_visible * scale)
+            : 0;
+
+        /* Must use surface logical coordinates (same calculations as
+           in get_csd_data(), but with different inputs) */
+        const int toplevel_min_width = roundf(border / scale) +
+                                       roundf(min_width / scale) +
+                                       roundf(border / scale);
+
+        const int toplevel_min_height = roundf(border / scale) +
+                                        roundf(title / scale) +
+                                        roundf(min_height / scale) +
+                                        roundf(border / scale);
+
+        const int toplevel_width = roundf(border / scale) +
+                                   roundf(term->width / scale) +
+                                   roundf(border / scale);
+
+        const int toplevel_height = roundf(border / scale) +
+                                    roundf(title / scale) +
+                                    roundf(term->height / scale) +
+                                    roundf(border / scale);
+
+        const int x = roundf(-border / scale);
+        const int y = roundf(-title / scale) - roundf(border / scale);
 
         xdg_toplevel_set_min_size(
             term->window->xdg_toplevel,
-            min_width / scale + 2 * border_width,
-            min_height / scale + title_height + 2 * border_width);
+            toplevel_min_width, toplevel_min_height);
 
         xdg_surface_set_window_geometry(
             term->window->xdg_surface,
-            -border_width,
-            -title_height - border_width,
-            term->width / term->scale + 2 * border_width,
-            term->height / term->scale + title_height + 2 * border_width);
+            x, y, toplevel_width, toplevel_height);
     }
 
     tll_free(term->normal.scroll_damage);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/foot/selection.c new/foot/selection.c
--- old/foot/selection.c        2023-07-21 08:57:03.000000000 +0200
+++ new/foot/selection.c        2023-07-30 13:18:55.000000000 +0200
@@ -1662,7 +1662,7 @@
         return;
     }
 
-    size_t len = strlen(selection);
+    size_t len = selection != NULL ? strlen(selection) : 0;
     size_t async_idx = 0;
 
     switch (async_write(fd, selection, len, &async_idx)) {
@@ -1701,7 +1701,6 @@
     struct seat *seat = data;
     const struct wl_clipboard *clipboard = &seat->clipboard;
 
-    xassert(clipboard->text != NULL);
     send_clipboard_or_primary(seat, fd, clipboard->text, "clipboard");
 }
 
@@ -1756,7 +1755,6 @@
     struct seat *seat = data;
     const struct wl_primary *primary = &seat->primary;
 
-    xassert(primary->text != NULL);
     send_clipboard_or_primary(seat, fd, primary->text, "primary");
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/foot/terminal.c new/foot/terminal.c
--- old/foot/terminal.c 2023-07-21 08:57:03.000000000 +0200
+++ new/foot/terminal.c 2023-07-30 13:18:55.000000000 +0200
@@ -784,8 +784,8 @@
         /* Use force, since cell-width/height may have changed */
         render_resize_force(
             term,
-            round(term->width / term->scale),
-            round(term->height / term->scale));
+            (int)roundf(term->width / term->scale),
+            (int)roundf(term->height / term->scale));
     }
     return true;
 }
@@ -825,7 +825,7 @@
         ? tll_back(win->on_outputs)
         : &tll_front(term->wl->monitors);
 
-    if (wayl_fractional_scaling(term->wl))
+    if (term_fractional_scaling(term))
         return mon->dpi.physical;
     else
         return mon->dpi.scaled;
@@ -880,12 +880,12 @@
 term_pt_or_px_as_pixels(const struct terminal *term,
                         const struct pt_or_px *pt_or_px)
 {
-    double scale = !term->font_is_sized_by_dpi ? term->scale : 1.;
-    double dpi = term->font_is_sized_by_dpi  ? term->font_dpi : 96.;
+    float scale = !term->font_is_sized_by_dpi ? term->scale : 1.;
+    float dpi = term->font_is_sized_by_dpi  ? term->font_dpi : 96.;
 
     return pt_or_px->px == 0
-        ? round(pt_or_px->pt * scale * dpi / 72)
-        : pt_or_px->px * scale;
+        ? (int)roundf(pt_or_px->pt * scale * dpi / 72)
+        : (int)roundf(pt_or_px->px * scale);
 }
 
 struct font_load_data {
@@ -932,7 +932,7 @@
 
             if (use_px_size)
                 snprintf(size, sizeof(size), ":pixelsize=%d",
-                         (int)round(term->font_sizes[i][j].px_size * scale));
+                         (int)roundf(term->font_sizes[i][j].px_size * scale));
             else
                 snprintf(size, sizeof(size), ":size=%.2f",
                          term->font_sizes[i][j].pt_size * scale);
@@ -2078,6 +2078,16 @@
 }
 
 bool
+term_fractional_scaling(const struct terminal *term)
+{
+#if defined(HAVE_FRACTIONAL_SCALE)
+    return term->wl->fractional_scale_manager != NULL && term->window->scale > 
0.;
+#else
+    return false;
+#endif
+}
+
+bool
 term_update_scale(struct terminal *term)
 {
     const struct wl_window *win = term->window;
@@ -2093,7 +2103,7 @@
      *  - if there aren’t any outputs available, use 1.0
      */
     const float new_scale =
-        (wayl_fractional_scaling(term->wl) && win->scale > 0.
+        (term_fractional_scaling(term)
          ? win->scale
          : (tll_length(win->on_outputs) > 0
             ? tll_back(win->on_outputs)->scale
@@ -2166,6 +2176,17 @@
     render_refresh(term);
 }
 
+int
+term_font_baseline(const struct terminal *term)
+{
+    const struct fcft_font *font = term->fonts[0];
+    const int line_height = term->cell_height;
+    const int font_height = max(font->height, font->ascent + font->descent);
+    const int glyph_top_y = round((line_height - font_height) / 2.);
+
+    return term->font_y_ofs + glyph_top_y + font->ascent;
+}
+
 void
 term_damage_rows(struct terminal *term, int start, int end)
 {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/foot/terminal.h new/foot/terminal.h
--- old/foot/terminal.h 2023-07-21 08:57:03.000000000 +0200
+++ new/foot/terminal.h 2023-07-30 13:18:55.000000000 +0200
@@ -736,12 +736,14 @@
 bool term_paste_data_to_slave(
     struct terminal *term, const void *data, size_t len);
 
+bool term_fractional_scaling(const struct terminal *term);
 bool term_update_scale(struct terminal *term);
 bool term_font_size_increase(struct terminal *term);
 bool term_font_size_decrease(struct terminal *term);
 bool term_font_size_reset(struct terminal *term);
 bool term_font_dpi_changed(struct terminal *term, float old_scale);
 void term_font_subpixel_changed(struct terminal *term);
+int term_font_baseline(const struct terminal *term);
 
 int term_pt_or_px_as_pixels(
     const struct terminal *term, const struct pt_or_px *pt_or_px);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/foot/tests/test-config.c new/foot/tests/test-config.c
--- old/foot/tests/test-config.c        2023-07-21 08:57:03.000000000 +0200
+++ new/foot/tests/test-config.c        2023-07-30 13:18:55.000000000 +0200
@@ -265,7 +265,7 @@
 }
 
 static void
-test_double(struct context *ctx, bool (*parse_fun)(struct context *ctx),
+test_float(struct context *ctx, bool (*parse_fun)(struct context *ctx),
             const char *key, const float *ptr)
 {
     ctx->key = key;
@@ -580,7 +580,7 @@
 
     test_uint32(&ctx, &parse_section_scrollback, "lines",
                 &conf.scrollback.lines);
-    test_double(&ctx, parse_section_scrollback, "multiplier", 
&conf.scrollback.multiplier);
+    test_float(&ctx, parse_section_scrollback, "multiplier", 
&conf.scrollback.multiplier);
 
     test_enum(
         &ctx, &parse_section_scrollback, "indicator-position",
@@ -1312,7 +1312,7 @@
                  RENDER_TIMER_BOTH},
         (int *)&conf.tweak.render_timer);
 
-    test_double(&ctx, &parse_section_tweak, "box-drawing-base-thickness",
+    test_float(&ctx, &parse_section_tweak, "box-drawing-base-thickness",
                 &conf.tweak.box_drawing_base_thickness);
     test_boolean(&ctx, &parse_section_tweak, "box-drawing-solid-shades",
         &conf.tweak.box_drawing_solid_shades);
@@ -1345,6 +1345,9 @@
     test_boolean(&ctx, &parse_section_tweak, "font-monospace-warn",
                  &conf.tweak.font_monospace_warn);
 
+    test_float(&ctx, &parse_section_tweak, "bold-text-in-bright-amount",
+               &conf.bold_in_bright.amount);
+
 #if 0 /* Must be equal to, or less than INT32_MAX */
     test_uint32(&ctx, &parse_section_tweak, "max-shm-pool-size-mb",
                 &conf.tweak.max_shm_pool_size);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/foot/vt.c new/foot/vt.c
--- old/foot/vt.c       2023-07-21 08:57:03.000000000 +0200
+++ new/foot/vt.c       2023-07-30 13:18:55.000000000 +0200
@@ -913,6 +913,16 @@
 {
     // wc = ((utf8[0] & 0xf) << 12) | ((utf8[1] & 0x3f) << 6) | (utf8[2] & 
0x3f)
     term->vt.utf8 |= c & 0x3f;
+
+    const char32_t utf32 = term->vt.utf8;
+    if (unlikely(utf32 >= 0xd800 && utf32 <= 0xdfff)) {
+        /* Invalid sequence - invalid UTF-16 surrogate halves */
+        return;
+    }
+
+    /* Note: the E0 range contains overlong encodings. We don’t try to
+       detect, as they’ll still decode to valid UTF-32. */
+
     action_utf8_print(term, term->vt.utf8);
 }
 
@@ -942,6 +952,17 @@
 {
     // wc = ((utf8[0] & 7) << 18) | ((utf8[1] & 0x3f) << 12) | ((utf8[2] & 
0x3f) << 6) | (utf8[3] & 0x3f);
     term->vt.utf8 |= c & 0x3f;
+
+    const char32_t utf32 = term->vt.utf8;
+
+    if (unlikely(utf32 > 0x10FFFF)) {
+        /* Invalid UTF-8 */
+        return;
+    }
+
+    /* Note: the F0 range contains overlong encodings. We don’t try to
+       detect, as they’ll still decode to valid UTF-32. */
+
     action_utf8_print(term, term->vt.utf8);
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/foot/wayland.c new/foot/wayland.c
--- old/foot/wayland.c  2023-07-21 08:57:03.000000000 +0200
+++ new/foot/wayland.c  2023-07-30 13:18:55.000000000 +0200
@@ -57,7 +57,7 @@
 
     char pixelsize[32];
     snprintf(pixelsize, sizeof(pixelsize), "pixelsize=%u",
-             (int)round(conf->csd.title_height * scale * 1 / 2));
+             (int)roundf(conf->csd.title_height * scale * 1 / 2));
 
     LOG_DBG("loading CSD font \"%s:%s\" (old-scale=%.2f, scale=%.2f)",
             patterns[0], pixelsize, old_scale, scale);
@@ -315,15 +315,17 @@
             }
 
 #if defined(HAVE_FRACTIONAL_SCALE)
-            xassert(seat->pointer.surface.viewport == NULL);
-            seat->pointer.surface.viewport = wp_viewporter_get_viewport(
-                seat->wayl->viewporter, seat->pointer.surface.surf);
-
-            if (seat->pointer.surface.viewport == NULL) {
-                LOG_ERR("%s: failed to create pointer viewport", seat->name);
-                wl_surface_destroy(seat->pointer.surface.surf);
-                seat->pointer.surface.surf = NULL;
-                return;
+            if (seat->wayl->viewporter != NULL) {
+                xassert(seat->pointer.surface.viewport == NULL);
+                seat->pointer.surface.viewport = wp_viewporter_get_viewport(
+                    seat->wayl->viewporter, seat->pointer.surface.surf);
+
+                if (seat->pointer.surface.viewport == NULL) {
+                    LOG_ERR("%s: failed to create pointer viewport", 
seat->name);
+                    wl_surface_destroy(seat->pointer.surface.surf);
+                    seat->pointer.surface.surf = NULL;
+                    return;
+                }
             }
 #endif
 
@@ -351,8 +353,10 @@
             wl_surface_destroy(seat->pointer.surface.surf);
 
 #if defined(HAVE_FRACTIONAL_SCALE)
-            wp_viewport_destroy(seat->pointer.surface.viewport);
-            seat->pointer.surface.viewport = NULL;
+            if (seat->pointer.surface.viewport != NULL) {
+                wp_viewport_destroy(seat->pointer.surface.viewport);
+                seat->pointer.surface.viewport = NULL;
+            }
 #endif
 
             if (seat->pointer.theme != NULL)
@@ -416,7 +420,7 @@
          * buffer dimensions may not have been updated (in which case
          * render_size() normally shortcuts and returns early).
          */
-        render_resize_force(term, round(logical_width), round(logical_height));
+        render_resize_force(term, (int)roundf(logical_width), 
(int)roundf(logical_height));
     }
 
     else if (scale_updated) {
@@ -425,7 +429,7 @@
          * been updated, even though the window logical dimensions
          * haven’t changed.
          */
-        render_resize(term, round(logical_width), round(logical_height));
+        render_resize(term, (int)roundf(logical_width), 
(int)roundf(logical_height));
     }
 }
 
@@ -620,6 +624,8 @@
 static void
 xdg_output_handle_done(void *data, struct zxdg_output_v1 *xdg_output)
 {
+    struct monitor *mon = data;
+    update_terms_on_monitor(mon);
 }
 
 static void
@@ -1526,7 +1532,7 @@
         LOG_INFO(
             "%s: %dx%d+%dx%d@%dHz %s %.2f\" scale=%d, DPI=%.2f/%.2f 
(physical/scaled)",
             it->item.name, it->item.dim.px_real.width, 
it->item.dim.px_real.height,
-            it->item.x, it->item.y, (int)round(it->item.refresh),
+            it->item.x, it->item.y, (int)roundf(it->item.refresh),
             it->item.model != NULL ? it->item.model : it->item.description,
             it->item.inch, it->item.scale,
             it->item.dpi.physical, it->item.dpi.scaled);
@@ -1994,33 +2000,35 @@
     wayl_flush(wayl);
 }
 
-
-bool
-wayl_fractional_scaling(const struct wayland *wayl)
-{
-#if defined(HAVE_FRACTIONAL_SCALE)
-    return wayl->fractional_scale_manager != NULL;
-#else
-    return false;
-#endif
-}
-
-void
-wayl_surface_scale_explicit_width_height(
+static void
+surface_scale_explicit_width_height(
     const struct wl_window *win, const struct wayl_surface *surf,
-    int width, int height, float scale)
+    int width, int height, float scale, bool verify)
 {
-
-    if (wayl_fractional_scaling(win->term->wl) && win->scale > 0.) {
+    if (term_fractional_scaling(win->term)) {
 #if defined(HAVE_FRACTIONAL_SCALE)
         LOG_DBG("scaling by a factor of %.2f using fractional scaling "
                 "(width=%d, height=%d) ", scale, width, height);
 
+        if (verify) {
+            if ((int)roundf(scale * (int)roundf(width / scale)) != width) {
+                BUG("width=%d is not valid with scaling factor %.2f (%d != 
%d)",
+                    width, scale,
+                    (int)roundf(scale * (int)roundf(width / scale)),
+                    width);
+            }
+
+            if ((int)roundf(scale * (int)roundf(height / scale)) != height) {
+                BUG("height=%d is not valid with scaling factor %.2f (%d != 
%d)",
+                    height, scale,
+                    (int)roundf(scale * (int)roundf(height / scale)),
+                    height);
+            }
+        }
+
         wl_surface_set_buffer_scale(surf->surf, 1);
         wp_viewport_set_destination(
-            surf->viewport,
-            round((float)width / scale),
-            round((float)height / scale));
+            surf->viewport, roundf(width / scale), roundf(height / scale));
 #else
         BUG("wayl_fraction_scaling() returned true, "
             "but fractional scaling was not available at compile time");
@@ -2029,9 +2037,9 @@
         LOG_DBG("scaling by a factor of %.2f using legacy mode "
                 "(width=%d, height=%d)", scale, width, height);
 
-        xassert(scale == floor(scale));
+        xassert(scale == floorf(scale));
 
-        const int iscale = (int)scale;
+        const int iscale = (int)floorf(scale);
         xassert(width % iscale == 0);
         xassert(height % iscale == 0);
 
@@ -2040,11 +2048,19 @@
 }
 
 void
+wayl_surface_scale_explicit_width_height(
+    const struct wl_window *win, const struct wayl_surface *surf,
+    int width, int height, float scale)
+{
+    surface_scale_explicit_width_height(win, surf, width, height, scale, 
false);
+}
+
+void
 wayl_surface_scale(const struct wl_window *win, const struct wayl_surface 
*surf,
                    const struct buffer *buf, float scale)
 {
-    wayl_surface_scale_explicit_width_height(
-        win, surf, buf->width, buf->height, scale);
+    surface_scale_explicit_width_height(
+        win, surf, buf->width, buf->height, scale, true);
 }
 
 void

Reply via email to