@@ -348,3 +348,144 @@ mirb_term_clear_below(void)
348348{
349349printf("\033[J");
350350}
351+352+#if !defined(_WIN32) && !defined(_WIN64)
353+/*
354+ * Query terminal background color using OSC 11 escape sequence
355+ *
356+ * Protocol:
357+ * Send: ESC ] 11 ; ? ESC \ (or BEL instead of ESC \)
358+ * Recv: ESC ] 11 ; rgb:RRRR/GGGG/BBBB ESC \
359+ *
360+ * The response uses 16-bit color values (0000-FFFF per component).
361+ * Some terminals use 8-bit (00-FF) format instead.
362+ */
363+mirb_bg_color
364+mirb_term_query_bg_color(int timeout_ms)
365+{
366+struct termios old_term, new_term;
367+char buf[64];
368+size_t total = 0;
369+ssize_t n;
370+int r, g, b;
371+mirb_bg_color result = MIRB_BG_UNKNOWN;
372+fd_set fds;
373+struct timeval tv;
374+const char *p;
375+376+/* Must be a terminal */
377+if (!isatty(STDIN_FILENO) || !isatty(STDOUT_FILENO)) {
378+return MIRB_BG_UNKNOWN;
379+ }
380+381+/* Save original terminal settings */
382+if (tcgetattr(STDIN_FILENO, &old_term) < 0) {
383+return MIRB_BG_UNKNOWN;
384+ }
385+386+/* Flush any pending input first */
387+tcflush(STDIN_FILENO, TCIFLUSH);
388+389+/* Disable echo and canonical mode for raw read */
390+new_term = old_term;
391+new_term.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL);
392+new_term.c_iflag &= ~(IXON | IXOFF | ICRNL);
393+new_term.c_cc[VMIN] = 0;
394+new_term.c_cc[VTIME] = 0;
395+396+/* TCSAFLUSH: flush I/O and apply settings */
397+if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &new_term) < 0) {
398+return MIRB_BG_UNKNOWN;
399+ }
400+401+/* Wait for terminal settings to take effect */
402+tcdrain(STDOUT_FILENO);
403+404+/* Send OSC 11 query: ESC ] 11 ; ? ESC \ */
405+if (write(STDOUT_FILENO, "\033]11;?\033\\", 8) != 8) {
406+ goto restore;
407+ }
408+/* Ensure query is sent to terminal */
409+tcdrain(STDOUT_FILENO);
410+/* Give terminal time to process and respond */
411+usleep(50000); /* 50ms */
412+413+/* Read response with timeout - loop to get complete response */
414+while (total < sizeof(buf) - 1) {
415+int sel;
416+FD_ZERO(&fds);
417+FD_SET(STDIN_FILENO, &fds);
418+tv.tv_sec = timeout_ms / 1000;
419+tv.tv_usec = (timeout_ms % 1000) * 1000;
420+421+sel = select(STDIN_FILENO + 1, &fds, NULL, NULL, &tv);
422+if (sel < 0) {
423+if (errno == EINTR) continue; /* Retry on signal interrupt */
424+break; /* Other error */
425+ }
426+if (sel == 0) break; /* Timeout */
427+428+n = read(STDIN_FILENO, buf + total, sizeof(buf) - 1 - total);
429+if (n <= 0) {
430+if (n < 0 && errno == EINTR) continue; /* Retry on signal interrupt */
431+break;
432+ }
433+total += (size_t)n;
434+435+/* Check for terminator: ESC \ (0x1b 0x5c) or BEL (0x07) */
436+if (total >= 2 && buf[total-2] == '\033' && buf[total-1] == '\\') break;
437+if (total >= 1 && buf[total-1] == '\007') break;
438+439+/* Reduce timeout for subsequent reads */
440+timeout_ms = 10;
441+ }
442+443+if (total == 0) {
444+ goto restore;
445+ }
446+buf[total] = '\0';
447+448+/* Parse response: look for "rgb:" followed by hex values */
449+p = strstr(buf, "rgb:");
450+if (p) {
451+p += 4;
452+/* Try 16-bit format: rgb:RRRR/GGGG/BBBB */
453+if (sscanf(p, "%4x/%4x/%4x", &r, &g, &b) == 3) {
454+/* Normalize to 8-bit range */
455+r >>= 8; g >>= 8; b >>= 8;
456+ }
457+/* Try 8-bit format: rgb:RR/GG/BB */
458+else if (sscanf(p, "%2x/%2x/%2x", &r, &g, &b) == 3) {
459+/* Already 8-bit */
460+ }
461+else {
462+ goto restore;
463+ }
464+465+/* Calculate relative luminance (ITU-R BT.709 simplified) */
466+/* Y = 0.2126*R + 0.7152*G + 0.0722*B */
467+/* Scale: 0-255 input, threshold at ~127.5 */
468+int luminance = (2126 * r + 7152 * g + 722 * b) / 10000;
469+result = (luminance < 128) ? MIRB_BG_DARK : MIRB_BG_LIGHT;
470+ }
471+472+restore:
473+/* Flush any remaining input before restoring terminal */
474+tcflush(STDIN_FILENO, TCIFLUSH);
475+tcsetattr(STDIN_FILENO, TCSAFLUSH, &old_term);
476+return result;
477+}
478+479+#else /* Windows */
480+481+mirb_bg_color
482+mirb_term_query_bg_color(int timeout_ms)
483+{
484+ (void)timeout_ms;
485+/* Windows Terminal supports OSC 11, but implementation requires
486+ * different I/O handling. For now, return unknown and rely on
487+ * fallback detection methods. */
488+return MIRB_BG_UNKNOWN;
489+}
490+491+#endif /* _WIN32 */