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

Gtk4中GtkGestureClick点击GtkImage实现窗口最小化与关闭失效问题

GtkImage绑定GtkGestureClick后窗口恢复关闭功能失效问题排查

问题描述

通过点击GtkImage实现窗口最小化与关闭操作,为两个GtkImage分别绑定GtkGestureClick事件:

  • 最小化图标功能正常
  • 窗口从最小化状态恢复后,关闭图标点击无响应

演示代码

#include <gtk/gtk.h>
GtkWidget *window, *grid;

// window close cb function //
static void close_app_cb (GtkGesture *click,
                          int n_press,
                          gdouble x,
                          gdouble y,
                          gpointer user_data)
{
    GApplication *app=g_application_get_default();
    g_application_quit(app);
}
// window minimize cb function //
static void minimize (GtkGestureClick *gesture,
                      gint n_press,
                      gdouble x,
                      gdouble y,
                      gpointer   data)
{
      gtk_window_minimize ((GtkWindow *)window);
}

static void
activate (GtkApplication* app,
          gpointer        user_data)
{
  window = gtk_application_window_new (app);
  gtk_window_set_decorated ((GtkWindow *)window, FALSE);
  gtk_window_set_default_size (GTK_WINDOW (window), 300, 300);

  grid = gtk_grid_new ();
  gtk_window_set_child ((GtkWindow   *)window, grid);
  gtk_grid_set_row_spacing ((GtkGrid *)grid, 15);

 /* window close icon */
  GtkWidget *c_btn = gtk_image_new_from_icon_name ("window-close-symbolic");
  gtk_image_set_icon_size (GTK_IMAGE (c_btn), GTK_ICON_SIZE_LARGE);
  gtk_grid_attach ((GtkGrid *)grid, c_btn, 1, 0, 1, 1);

  GtkGesture *gesture1;
  gesture1 = gtk_gesture_click_new ();
  g_signal_connect (gesture1, "pressed", G_CALLBACK (close_app_cb), NULL);
  gtk_widget_add_controller (c_btn, GTK_EVENT_CONTROLLER (gesture1));

 /* window minimize icon */
  GtkWidget *m_btn = gtk_image_new_from_icon_name ("window-minimize-symbolic");
  gtk_image_set_icon_size (GTK_IMAGE (m_btn), GTK_ICON_SIZE_LARGE);
  gtk_grid_attach ((GtkGrid *)grid, m_btn, 0, 0, 1, 1);

  GtkGesture *gesture2;
  gesture2 = gtk_gesture_click_new ();
  g_signal_connect (gesture2, "pressed", G_CALLBACK (minimize), NULL);
  gtk_widget_add_controller (m_btn, GTK_EVENT_CONTROLLER (gesture2));

  gtk_window_present (GTK_WINDOW(window));
}

int
main (int    argc,
      char **argv)
{
  GtkApplication *app;
  int status;
  #if GLIB_CHECK_VERSION(2, 74, 0)
      app = gtk_application_new ("org.gtk.example", G_APPLICATION_DEFAULT_FLAGS); 
  #else
        app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE); 
  #endif
  g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
  status = g_application_run (G_APPLICATION (app), argc, argv);
  g_object_unref (app);
  return status;
}

问题根源

GtkGestureClick属于手势识别控制器,会跟踪完整的手势生命周期(按下→释放)。当点击最小化图标后,窗口立即被最小化,此时手势的状态会被标记为中断;恢复窗口后,该手势控制器未正确重置状态,导致后续点击关闭图标时,无法触发pressed信号。

解决方法

方法1:为GtkGestureClick指定监听的鼠标按钮

通过gtk_gesture_single_set_button明确指定监听左键点击,强制手势控制器重置状态逻辑:

/* 关闭图标手势 */
GtkGesture *gesture1 = gtk_gesture_click_new();
gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(gesture1), GDK_BUTTON_PRIMARY);
g_signal_connect(gesture1, "pressed", G_CALLBACK(close_app_cb), NULL);
gtk_widget_add_controller(c_btn, GTK_EVENT_CONTROLLER(gesture1));

/* 最小化图标手势 */
GtkGesture *gesture2 = gtk_gesture_click_new();
gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(gesture2), GDK_BUTTON_PRIMARY);
g_signal_connect(gesture2, "pressed", G_CALLBACK(minimize), NULL);
gtk_widget_add_controller(m_btn, GTK_EVENT_CONTROLLER(gesture2));

方法2:改用GtkEventControllerButton(更推荐)

对于简单的点击需求,使用基础的GtkEventControllerButton替代手势控制器,避免复杂的手势状态跟踪逻辑:

  1. 修改回调函数:
static void close_app_btn_cb(GtkEventControllerButton *controller,
                             guint button,
                             guint n_press,
                             gpointer user_data)
{
    if (button == GDK_BUTTON_PRIMARY) {
        GApplication *app = g_application_get_default();
        g_application_quit(app);
    }
}

static void minimize_btn_cb(GtkEventControllerButton *controller,
                            guint button,
                            guint n_press,
                            gpointer user_data)
{
    if (button == GDK_BUTTON_PRIMARY) {
        gtk_window_minimize(GTK_WINDOW(window));
    }
}
  1. 替换控制器创建代码:
/* 关闭图标控制器 */
GtkEventController *close_controller = gtk_event_controller_button_new();
g_signal_connect(close_controller, "pressed", G_CALLBACK(close_app_btn_cb), NULL);
gtk_widget_add_controller(c_btn, close_controller);

/* 最小化图标控制器 */
GtkEventController *minimize_controller = gtk_event_controller_button_new();
g_signal_connect(minimize_controller, "pressed", G_CALLBACK(minimize_btn_cb), NULL);
gtk_widget_add_controller(m_btn, minimize_controller);

验证结果

两种方法均可解决窗口恢复后关闭图标无响应的问题,方法2更适合简单点击场景,逻辑更稳定。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 10:25:00