From 2920ca8d4c70eb63212c89adb6477e3bbd9295b7 Mon Sep 17 00:00:00 2001
From: Sergey Fedorov <barracuda@macos-powerpc.org>
Date: Mon, 27 Jul 2026 16:09:55 +0000
Subject: [PATCH 11/11] build: replace bool:N bitfields with uint8_t:N across
 the tree

bool is 4 bytes on Darwin/PowerPC (GCC's -mone-byte-bool docs), and a
plain enum's default underlying type is (at least) unsigned int
everywhere. PowerPC's ABI allocates each bitfield's storage unit
sized to match its declared base type, so any bool:N or plain-enum:N
bitfield gets its own 4-byte unit there instead of packing into a
shared byte with its neighbors -- breaking every size-sensitive
struct using this pattern (struct attributes and
bits_affecting_ascii_printer in terminal.h both have their own
_Static_assert; client_data in client-protocol.h is wire-protocol
data between footclient/foot --server with its own size assert;
kitty_key_data in kitty-keymap.h likewise). Elsewhere (wayland.h,
config.h) there's no hard size assertion, but the same fix keeps
these structs at their intended, documented byte budget instead of
silently ballooning on this target.

uint8_t's size/alignment is 1 byte on every target, sidestepping
both the Apple-specific bool quirk and the generic PowerPC
bitfield-storage-unit rule. Named bitfield access (.sixels, .osc8,
etc.) and the color_source enum values stored in fg_src/bg_src are
unaffected; only the storage type changed. Bit-field allocation order
differs between big-endian PowerPC and little-endian x86/ARM, but
none of these fields are ever serialized or bit-picked by position --
only individual named-field access and whole-value (!=0/==0)
comparisons are used, both of which are layout-independent.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U6fuL1PtRJHhr97gAGyS1h
---
 client-protocol.h |  14 ++++-
 config.h          |  24 ++++----
 kitty-keymap.h    |   7 ++-
 terminal.h        | 136 +++++++++++++++++++++++++++-------------------
 wayland.h         |  34 ++++++------
 5 files changed, 126 insertions(+), 89 deletions(-)

diff --git a/client-protocol.h b/client-protocol.h
index efd601d7..12a6f153 100644
--- a/client-protocol.h
+++ b/client-protocol.h
@@ -10,9 +10,17 @@ struct client_string {
 };
 
 struct client_data {
-    bool hold:1;
-    bool no_wait:1;
-    bool xdga_token:1;
+    /*
+     * uint8_t, not bool: bool is 4 bytes on Darwin/PowerPC (see
+     * GCC's -mone-byte-bool docs), which combined with PowerPC's
+     * bitfield-storage-unit-matches-base-type rule would force each
+     * bool:1 into its own 4-byte unit instead of packing into the
+     * same byte as the other bitfields below, breaking the
+     * _Static_assert on struct size.
+     */
+    uint8_t hold:1;
+    uint8_t no_wait:1;
+    uint8_t xdga_token:1;
     uint8_t reserved:5;
 
     uint8_t token_len;
diff --git a/config.h b/config.h
index f8e99df3..fe2fbede 100644
--- a/config.h
+++ b/config.h
@@ -184,12 +184,12 @@ struct color_theme {
     } search_box;
 
     struct {
-        bool cursor:1;
-        bool jump_label:1;
-        bool scrollback_indicator:1;
-        bool url:1;
-        bool search_box_no_match:1;
-        bool search_box_match:1;
+        uint8_t cursor:1;
+        uint8_t jump_label:1;
+        uint8_t scrollback_indicator:1;
+        uint8_t url:1;
+        uint8_t search_box_no_match:1;
+        uint8_t search_box_match:1;
         uint8_t dim;
     } use_custom;
 
@@ -395,12 +395,12 @@ struct config {
         bool double_click_to_maximize;
 
         struct {
-            bool title_set:1;
-            bool buttons_set:1;
-            bool minimize_set:1;
-            bool maximize_set:1;
-            bool close_set:1;
-            bool border_set:1;
+            uint8_t title_set:1;
+            uint8_t buttons_set:1;
+            uint8_t minimize_set:1;
+            uint8_t maximize_set:1;
+            uint8_t close_set:1;
+            uint8_t border_set:1;
             uint32_t title;
             uint32_t buttons;
             uint32_t minimize;
diff --git a/kitty-keymap.h b/kitty-keymap.h
index 3420d01f..e5a21f40 100644
--- a/kitty-keymap.h
+++ b/kitty-keymap.h
@@ -8,7 +8,12 @@ struct kitty_key_data {
     xkb_keysym_t sym;
     uint16_t key;
     uint8_t final:7;
-    bool is_modifier:1;
+    /*
+     * uint8_t, not bool: bool is 4 bytes on Darwin/PowerPC, which
+     * would force this bitfield into its own storage unit instead of
+     * sharing a byte with final:7 above, breaking the size assert.
+     */
+    uint8_t is_modifier:1;
 } __attribute__((packed));
 
 _Static_assert(sizeof(struct kitty_key_data) == 7, "bad size");
diff --git a/terminal.h b/terminal.h
index e6a992e3..7424e896 100644
--- a/terminal.h
+++ b/terminal.h
@@ -74,24 +74,36 @@ enum color_source {
  *  misses)
  *
  * Note that the members are laid out optimized for x86
+ *
+ * All single-bit members use uint8_t (not bool, not enum
+ * color_source) so they pack tightly into a single byte alongside
+ * the surrounding bitfields on every target: bool is 4 bytes on
+ * Darwin/PowerPC, and a plain enum's default underlying type is
+ * always (at least) `unsigned int`; PowerPC's ABI allocates each
+ * bitfield's storage unit sized to match its declared base type, so
+ * either would otherwise inflate this struct well past the
+ * asserted 8 bytes there. fg_src/bg_src still only ever hold
+ * enum color_source values (COLOR_DEFAULT et al); the field is
+ * declared uint8_t purely to control storage, not because the
+ * values stored are no longer semantically an enum color_source.
  */
 struct attributes {
-    bool bold:1;
-    bool dim:1;
-    bool italic:1;
-    bool underline:1;
-    bool strikethrough:1;
-    bool blink:1;
-    bool conceal:1;
-    bool reverse:1;
+    uint8_t bold:1;
+    uint8_t dim:1;
+    uint8_t italic:1;
+    uint8_t underline:1;
+    uint8_t strikethrough:1;
+    uint8_t blink:1;
+    uint8_t conceal:1;
+    uint8_t reverse:1;
     uint32_t fg:24;
 
-    bool clean:1;
-    enum color_source fg_src:2;
-    enum color_source bg_src:2;
-    bool confined:1;
-    bool selected:1;
-    bool url:1;
+    uint8_t clean:1;
+    uint8_t fg_src:2;
+    uint8_t bg_src:2;
+    uint8_t confined:1;
+    uint8_t selected:1;
+    uint8_t url:1;
     uint32_t bg:24;
 };
 static_assert(sizeof(struct attributes) == 8, "VT attribute struct too large");
@@ -442,12 +454,18 @@ struct terminal {
     void (*ascii_printer)(struct terminal *term, char32_t c);
     union {
         struct {
-            bool sixels:1;
-            bool osc8:1;
-            bool underline_style:1;
-            bool underline_color:1;
-            bool insert_mode:1;
-            bool charset:1;
+            /*
+             * uint8_t, not bool: bool is 4 bytes on Darwin/PowerPC,
+             * which would make this bitfield struct larger than
+             * uint8_t value below and break term_update_ascii_printer()'s
+             * _Static_assert.
+             */
+            uint8_t sixels:1;
+            uint8_t osc8:1;
+            uint8_t underline_style:1;
+            uint8_t underline_color:1;
+            uint8_t insert_mode:1;
+            uint8_t charset:1;
         };
         uint8_t value;
     } bits_affecting_ascii_printer;
@@ -546,42 +564,48 @@ struct terminal {
     bool bell_action_enabled;
     bool report_theme_changes;
 
-    /* Saved DECSET modes - we save the SET state */
+    /*
+     * Saved DECSET modes - we save the SET state.
+     *
+     * uint8_t, not bool, throughout: bool is 4 bytes on
+     * Darwin/PowerPC, which would force each bitfield into its own
+     * storage unit there instead of packing tightly.
+     */
     struct {
-        bool origin:1;
-        bool application_cursor_keys:1;
-        bool application_keypad_keys:1;
-        bool reverse:1;
-        bool show_cursor:1;
-        bool reverse_wrap:1;
-        bool auto_margin:1;
-        bool cursor_blink:1;
-        bool bracketed_paste:1;
-        bool focus_events:1;
-        bool alt_scrolling:1;
+        uint8_t origin:1;
+        uint8_t application_cursor_keys:1;
+        uint8_t application_keypad_keys:1;
+        uint8_t reverse:1;
+        uint8_t show_cursor:1;
+        uint8_t reverse_wrap:1;
+        uint8_t auto_margin:1;
+        uint8_t cursor_blink:1;
+        uint8_t bracketed_paste:1;
+        uint8_t focus_events:1;
+        uint8_t alt_scrolling:1;
         //bool mouse_x10:1;
-        bool mouse_click:1;
-        bool mouse_drag:1;
-        bool mouse_motion:1;
+        uint8_t mouse_click:1;
+        uint8_t mouse_drag:1;
+        uint8_t mouse_motion:1;
         //bool mouse_utf8:1;
-        bool mouse_sgr:1;
-        bool mouse_urxvt:1;
-        bool mouse_sgr_pixels:1;
-        bool meta_eight_bit:1;
-        bool meta_esc_prefix:1;
-        bool num_lock_modifier:1;
-        bool bell_action_enabled:1;
-        bool alt_screen:1;
-        bool ime:1;
-        bool app_sync_updates:1;
-        bool grapheme_shaping:1;
-        bool report_theme_changes:1;
-
-        bool size_notifications:1;
-
-        bool sixel_display_mode:1;
-        bool sixel_private_palette:1;
-        bool sixel_cursor_right_of_graphics:1;
+        uint8_t mouse_sgr:1;
+        uint8_t mouse_urxvt:1;
+        uint8_t mouse_sgr_pixels:1;
+        uint8_t meta_eight_bit:1;
+        uint8_t meta_esc_prefix:1;
+        uint8_t num_lock_modifier:1;
+        uint8_t bell_action_enabled:1;
+        uint8_t alt_screen:1;
+        uint8_t ime:1;
+        uint8_t app_sync_updates:1;
+        uint8_t grapheme_shaping:1;
+        uint8_t report_theme_changes:1;
+
+        uint8_t size_notifications:1;
+
+        uint8_t sixel_display_mode:1;
+        uint8_t sixel_private_palette:1;
+        uint8_t sixel_cursor_right_of_graphics:1;
     } xtsave;
 
     bool window_title_has_been_set;
@@ -810,9 +834,9 @@ struct terminal {
         int pan;
         int pad;
 
-        bool scrolling:1;                 /* Private mode 80 */
-        bool use_private_palette:1;       /* Private mode 1070 */
-        bool cursor_right_of_graphics:1;  /* Private mode 8452 */
+        uint8_t scrolling:1;                 /* Private mode 80 */
+        uint8_t use_private_palette:1;       /* Private mode 1070 */
+        uint8_t cursor_right_of_graphics:1;  /* Private mode 8452 */
 
         unsigned params[5];  /* Collected parameters, for RASTER, COLOR_SPEC */
         unsigned param;      /* Currently collecting parameter, for RASTER, COLOR_SPEC and REPEAT */
diff --git a/wayland.h b/wayland.h
index 9cbd1023..681e8388 100644
--- a/wayland.h
+++ b/wayland.h
@@ -393,8 +393,8 @@ struct wl_window {
     } csd;
 
     struct {
-        bool maximize:1;
-        bool minimize:1;
+        uint8_t maximize:1;
+        uint8_t minimize:1;
     } wm_capabilities;
 
     struct wayl_sub_surface search;
@@ -425,20 +425,20 @@ struct wl_window {
     struct {
         int width;
         int height;
-        bool is_activated:1;
-        bool is_fullscreen:1;
-        bool is_maximized:1;
-        bool is_resizing:1;
+        uint8_t is_activated:1;
+        uint8_t is_fullscreen:1;
+        uint8_t is_maximized:1;
+        uint8_t is_resizing:1;
 
-        bool is_tiled_top:1;
-        bool is_tiled_bottom:1;
-        bool is_tiled_left:1;
-        bool is_tiled_right:1;
+        uint8_t is_tiled_top:1;
+        uint8_t is_tiled_bottom:1;
+        uint8_t is_tiled_left:1;
+        uint8_t is_tiled_right:1;
 
-        bool is_constrained_top:1;
-        bool is_constrained_bottom:1;
-        bool is_constrained_left:1;
-        bool is_constrained_right:1;
+        uint8_t is_constrained_top:1;
+        uint8_t is_constrained_bottom:1;
+        uint8_t is_constrained_left:1;
+        uint8_t is_constrained_right:1;
 
         enum csd_mode csd_mode;
     } configure;
@@ -514,9 +514,9 @@ struct wayland {
     /* WL_SHM >= 2 */
     bool use_shm_release;
 
-    bool shm_have_argb2101010:1;
-    bool shm_have_abgr2101010:1;
-    bool shm_have_abgr161616:1;
+    uint8_t shm_have_argb2101010:1;
+    uint8_t shm_have_abgr2101010:1;
+    uint8_t shm_have_abgr161616:1;
 };
 
 struct wayland *wayl_init(
-- 
2.43.0

