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

如何让GtkWindow自动移动到当前聚焦的工作区?

问题:Gtk窗口无法自动跟随当前工作区切换

我想实现让Gtk窗口自动移动到当前聚焦的工作区——也就是切换工作区时,窗口能自动转移到新的工作区,但编写的代码无法正常运行,恳请帮忙排查问题?

#include <gtk/gtk.h>
#include <gdk/x11/gdkx.h>

int update (gpointer user_data){
    printf ("Timer\n");

    GtkNative *native = gtk_widget_get_native ((GtkWidget* )user_data);
    GdkSurface *surface = gtk_native_get_surface ((GtkNative *)native);

    //current desktop id
    guint32 desktopId = gdk_x11_surface_get_desktop (surface);
    printf ("Desktop Id %d\n", desktopId);

    gdk_x11_surface_move_to_current_desktop ((GdkSurface*)surface);
    //gdk_x11_surface_move_to_desktop (( GdkSurface *)surface, desktopId);
}


static void
activate (GtkApplication* app,
          gpointer        user_data){
  GtkWidget *window;

  window = gtk_application_window_new (app);
  gtk_window_set_title (GTK_WINDOW (window), "ColorPicker");
  gtk_window_set_default_size (GTK_WINDOW (window), 415, 300);
  gtk_window_present (GTK_WINDOW (window));

  g_timeout_add(512, (GSourceFunc)update, window);
  gtk_widget_show (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;
}

问题排查与修复方案

  • 回调函数返回值错误:update函数作为g_timeout_add的回调,必须返回gboolean类型(返回G_SOURCE_CONTINUE即1表示继续定时,返回G_SOURCE_REMOVE即0表示停止)。你的代码没有返回值,会导致定时器触发一次后就异常终止,无法持续检测工作区变化。
  • 工作区ID获取逻辑错误:gdk_x11_surface_get_desktop获取的是窗口当前所在的工作区ID,不是系统当前聚焦的工作区ID,这会导致你始终把窗口移回它原来的位置,而非新工作区。
  • 轮询效率低下:用定时器轮询是低效的方案,应该直接监听系统工作区切换的信号,精准响应事件。

修复后的代码

#include <gtk/gtk.h>
#include <gdk/x11/gdkx.h>

static void on_workspace_changed(GdkDisplay *display, GParamSpec *pspec, gpointer user_data) {
    GtkWidget *window = GTK_WIDGET(user_data);
    GtkNative *native = gtk_widget_get_native(window);
    if (!native) return;

    GdkSurface *surface = gtk_native_get_surface(native);
    if (!GDK_IS_X11_SURFACE(surface)) return;

    // 获取系统当前聚焦的工作区ID
    guint32 current_desktop = gdk_x11_display_get_current_desktop(GDK_X11_DISPLAY(display));
    // 将窗口移动到当前工作区
    gdk_x11_surface_move_to_desktop(surface, current_desktop);
}

static void activate(GtkApplication* app, gpointer user_data) {
    GtkWidget *window = gtk_application_window_new(app);
    gtk_window_set_title(GTK_WINDOW(window), "ColorPicker");
    gtk_window_set_default_size(GTK_WINDOW(window), 415, 300);
    gtk_window_present(GTK_WINDOW(window));

    // 监听系统工作区切换信号
    GdkDisplay *display = gdk_display_get_default();
    g_signal_connect(display, "notify::current-desktop", G_CALLBACK(on_workspace_changed), window);

    gtk_widget_show(window);
}

int main(int argc, char **argv) {
    GtkApplication *app = gtk_application_new("org.gtk.example", G_APPLICATION_FLAGS_NONE);
    g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
    int status = g_application_run(G_APPLICATION(app), argc, argv);
    g_object_unref(app);
    return status;
}

修复说明

  1. 改用notify::current-desktop信号监听工作区切换,替代定时器轮询,更高效精准
  2. 用gdk_x11_display_get_current_desktop获取系统当前活跃工作区ID,确保窗口移到正确位置
  3. 添加空值检查,避免空指针访问导致崩溃
  4. 移除冗余的定时器逻辑,简化代码结构

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 10:13:15