如何让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; }
修复说明
- 改用
notify::current-desktop信号监听工作区切换,替代定时器轮询,更高效精准 - 用
gdk_x11_display_get_current_desktop获取系统当前活跃工作区ID,确保窗口移到正确位置 - 添加空值检查,避免空指针访问导致崩溃
- 移除冗余的定时器逻辑,简化代码结构
内容的提问来源于stack exchange,提问作者dibyendu
相关产品推荐
相关产品推荐

