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强制激活:
- 添加Objective-C相关头文件到代码中:
#include <objc/objc.h> #include <objc/runtime.h> #include <gdk/gdkquartz.h>
- 实现强制焦点函数:
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); } }
- 在显示对话框后调用该函数:
gtk_widget_show_all(dialog); force_mac_dialog_focus(dialog);
- 编译时添加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
相关产品推荐
相关产品推荐

