You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GTK3 macOS对话框初始显示时内容无法交互问题求助

GTK3在MacOS Ventura下对话框焦点异常问题及解决方案

问题现象

  • 基于GTK3开发的跨平台应用,在MacOS Ventura系统中显示对话框时,主窗口关闭按钮变灰,对话框关闭按钮呈红色可正常点击,但点击对话框内部区域会将焦点切回主窗口,导致用户无法直接与对话框内容交互,需再次点击对话框才能操作
  • 该问题仅出现在MacOS Ventura,Linux和Windows平台对话框功能正常

已尝试无效的方法

  • 调用gtk_window_present()
  • 获取NSWindow句柄并调用makeKeyAndOrderFront:

环境信息

  • GTK3版本:MacPorts提供的3.24.34
  • 操作系统:MacOS Ventura(未测试其他MacOS版本)

代码示例

#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#include <gtk/gtk.h>

enum {
  STATE_OFF,
  STATE_PREP,
  STATE_PROCESS,
};

enum {
  RESPONSE_NONE,
  RESPONSE_CLOSE,
  RESPONSE_APPLY,
};

bool  done = false;
int   state = STATE_OFF;
int   response = RESPONSE_NONE;

static gboolean winclosecb (GtkWidget *window, GdkEvent *event, gpointer udata);
static void     buttonclickcb (GtkButton *b, gpointer udata);
static void     dialogrespcb (GtkDialog *d, gint responseid, gpointer udata);

int
main (int argc, char *argv [])
{
  argc = 0;
  GtkWidget   *window;
  GtkWidget   *vbox;
  GtkWidget   *hbox;
  GtkWidget   *widget;
  GtkWidget   *dialog = NULL;


  gtk_init (&argc, NULL);

  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_window_set_type_hint (GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_NORMAL);
  gtk_window_set_title (GTK_WINDOW (window), "test-mac-dialog");
  gtk_window_set_default_size (GTK_WINDOW (window), 500, 300);
  g_signal_connect (window, "delete-event", G_CALLBACK (winclosecb), NULL);

  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
  gtk_container_add (GTK_CONTAINER (window), vbox);

  hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);

  widget = gtk_button_new ();
  gtk_button_set_label (GTK_BUTTON (widget), "button");
  g_signal_connect (widget, "clicked", G_CALLBACK (buttonclickcb), NULL);
  gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);

  gtk_widget_show_all (window);
  gtk_window_present (GTK_WINDOW (window));

  while (! done) {
    gtk_main_iteration_do (FALSE);
    while (gtk_events_pending ()) {
      gtk_main_iteration_do (FALSE);
    }

    if (state == STATE_PROCESS) {
      if (response != RESPONSE_NONE) {
        response = RESPONSE_NONE;
        gtk_widget_hide (GTK_WIDGET (dialog));
        state = STATE_OFF;
      }
    }

    if (state == STATE_PREP) {
      if (dialog == NULL) {
        dialog = gtk_dialog_new ();
        gtk_window_set_title (GTK_WINDOW (dialog), "dialog");
        gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (window));
        gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
        gtk_dialog_add_button (GTK_DIALOG (dialog), "Close", RESPONSE_CLOSE);
        gtk_dialog_add_button (GTK_DIALOG (dialog), "Go", RESPONSE_APPLY);
        g_signal_connect (dialog, "response", G_CALLBACK (dialogrespcb), NULL);
      }
      gtk_widget_show_all (GTK_WIDGET (dialog));
      state = STATE_PROCESS;
    }
  }

  gtk_widget_destroy (window);
  gtk_main_iteration_do (FALSE);
  while (gtk_events_pending ()) {
    gtk_main_iteration_do (FALSE);
  }
  return 0;
}

static gboolean
winclosecb (GtkWidget *window, GdkEvent *event, gpointer udata)
{
  done = true;
  return true;
}

static void
buttonclickcb (GtkButton *b, gpointer udata)
{
  state = STATE_PREP;
}

static void
dialogrespcb (GtkDialog *d, gint responseid, gpointer udata)
{
  if (responseid == RESPONSE_CLOSE) {
    fprintf (stderr, "dialog close\n");
  }
  if (responseid == RESPONSE_APPLY) {
    fprintf (stderr, "dialog apply\n");
  }
  response = responseid;
}

编译脚本

#!/bin/bash

cc $(pkg-config --cflags gtk+-3.0) -o tt tt.c $(pkg-config --libs gtk+-3.0)

解决方案

方案1:修复自定义事件循环逻辑

自定义的事件循环迭代逻辑可能干扰GTK原生窗口焦点管理,建议在显示对话框后强制触发事件循环并设置焦点:
在gtk_widget_show_all(GTK_WIDGET(dialog));后添加以下代码:

gtk_window_present(GTK_WINDOW(dialog));
// 立即处理所有待处理事件,确保焦点设置生效
while (gtk_events_pending()) {
    gtk_main_iteration();
}

方案2:通过Objective-C底层API强制激活窗口

如果GTK API无效,可通过GDK Quartz后端获取NSWindow实例,调用MacOS原生API强制激活:

  1. 添加Objective-C相关头文件到代码中:
#include <objc/objc.h>
#include <objc/runtime.h>
#include <gdk/gdkquartz.h>
  1. 实现强制焦点函数:
void force_mac_dialog_focus(GtkWidget *dialog) {
    GdkWindow *gdk_window = gtk_widget_get_window(dialog);
    if (gdk_window && GDK_IS_QUARTZ_WINDOW(gdk_window)) {
        id ns_window = gdk_quartz_window_get_nswindow(gdk_window);
        // 调用MacOS原生API激活窗口并设置为焦点
        SEL make_key = sel_registerName("makeKeyAndOrderFront:");
        objc_msgSend(ns_window, make_key, NULL);
        SEL activate = sel_registerName("activateIgnoringOtherApps:");
        objc_msgSend(ns_window, activate, YES);
    }
}
  1. 在显示对话框后调用该函数:
gtk_widget_show_all(dialog);
force_mac_dialog_focus(dialog);
  1. 编译时添加Foundation框架链接参数:
    修改编译脚本,在链接部分添加-framework Foundation:
cc $(pkg-config --cflags gtk+-3.0) -o tt tt.c $(pkg-config --libs gtk+-3.0) -framework Foundation

方案3:更新GTK版本

MacPorts提供的GTK3.24.34可能存在Ventura系统特有的焦点bug,尝试更新到最新的GTK3版本:

sudo port upgrade gtk3

内容的提问来源于stack exchange,提问作者Brad Lanam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 06:42:05