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

如何通过子部件的GtkGestureClick实现GtkWindow拖拽移动(替换废弃API)

替换废弃的gtk_widget_translate_coordinates为gtk_widget_compute_point实现窗口拖拽

我通过点击并按住GtkWindow的子部件来拖拽移动窗口,现有代码可正常运行,但编译时出现警告:'gtk_widget_translate_coordinates已废弃,请使用gtk_widget_compute_point替代'。以下是修改后的代码,替换了废弃的API:

原代码

#include <gtk/gtk.h>

static void
start_move (GtkGestureClick *gesture,
            int n_press,
            double x,
            double y,
            gpointer   data)
{
  GtkWidget *widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
  GdkSurface *surface;
  GdkEvent *event;
  guint button;
  guint32 timestamp;

  gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
  surface = gtk_native_get_surface (gtk_widget_get_native (widget));
  event = gtk_event_controller_get_current_event (GTK_EVENT_CONTROLLER (gesture));
  if (gdk_event_get_event_type (event) == GDK_BUTTON_PRESS)
    button = gdk_button_event_get_button (event);
  else
    button = 0;
  timestamp = gdk_event_get_time (event);
  gtk_widget_translate_coordinates (widget, GTK_WIDGET (gtk_widget_get_root (widget)), x, y, &x, &y);
  gdk_toplevel_begin_move (GDK_TOPLEVEL (surface), gdk_event_get_device (event), button, x, y, timestamp);
  gtk_event_controller_reset (GTK_EVENT_CONTROLLER (gesture));
}


static void
activate (GtkApplication *app,
          gpointer        user_data)
{
  GtkWidget *window = gtk_application_window_new (app);
  gtk_window_set_title (GTK_WINDOW (window), "example");

  GtkWidget *fixed = gtk_fixed_new ();
  gtk_window_set_child ((GtkWindow    *)window, fixed);
  gtk_widget_set_size_request (fixed, 400, 200);

  GtkWidget *c_btn = gtk_button_new_from_icon_name ("window-close-symbolic");
  gtk_fixed_put (GTK_FIXED (fixed), c_btn, 125, 90);


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


  gtk_window_present ((GtkWindow*)window);
}

int
main (int    argc,
      char **argv)
{
  GtkApplication *app;
  int status;

  app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
  g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
  status = g_application_run (G_APPLICATION (app), argc, argv);
  g_object_unref (app);

  return status;
}

修改后的代码(替换废弃API)

#include <gtk/gtk.h>

static void
start_move (GtkGestureClick *gesture,
            int n_press,
            double x,
            double y,
            gpointer   data)
{
  GtkWidget *widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
  GdkSurface *surface;
  GdkEvent *event;
  guint button;
  guint32 timestamp;

  gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
  surface = gtk_native_get_surface (gtk_widget_get_native (widget));
  event = gtk_event_controller_get_current_event (GTK_EVENT_CONTROLLER (gesture));
  if (gdk_event_get_event_type (event) == GDK_BUTTON_PRESS)
    button = gdk_button_event_get_button (event);
  else
    button = 0;
  timestamp = gdk_event_get_time (event);
  
  // 替换废弃的gtk_widget_translate_coordinates为gtk_widget_compute_point
  GdkPoint point = { .x = (int)x, .y = (int)y };
  gtk_widget_compute_point(widget, GTK_WIDGET(gtk_widget_get_root(widget)), &point, &point);
  x = point.x;
  y = point.y;
  
  gdk_toplevel_begin_move (GDK_TOPLEVEL (surface), gdk_event_get_device (event), button, x, y, timestamp);
  gtk_event_controller_reset (GTK_EVENT_CONTROLLER (gesture));
}


static void
activate (GtkApplication *app,
          gpointer        user_data)
{
  GtkWidget *window = gtk_application_window_new (app);
  gtk_window_set_title (GTK_WINDOW (window), "example");

  GtkWidget *fixed = gtk_fixed_new ();
  gtk_window_set_child ((GtkWindow    *)window, fixed);
  gtk_widget_set_size_request (fixed, 400, 200);

  GtkWidget *c_btn = gtk_button_new_from_icon_name ("window-close-symbolic");
  gtk_fixed_put (GTK_FIXED (fixed), c_btn, 125, 90);


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


  gtk_window_present ((GtkWindow*)window);
}

int
main (int    argc,
      char **argv)
{
  GtkApplication *app;
  int status;

  app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
  g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
  status = g_application_run (G_APPLICATION (app), argc, argv);
  g_object_unref (app);

  return status;
}

关键修改说明

gtk_widget_compute_point的作用是将源部件坐标系下的点转换为目标部件坐标系下的点,核心用法:

  • 第一个参数:源部件(触发拖拽的子部件widget)
  • 第二个参数:目标部件(根窗口gtk_widget_get_root(widget),与原API的目标一致)
  • 第三个参数:输入点(需要先将double类型的点击位置转为int,构造GdkPoint)
  • 第四个参数:输出点(直接复用同一个GdkPoint变量存储转换后的结果)

转换完成后,将GdkPoint的x、y赋值回原变量,后续的窗口拖拽逻辑保持不变。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 02:32:04