根据https://developer.gnome.org/gdk3/stable/GdkScreen.html#gdk-screen-get-active-window,
gdk_screen_get_active_window自版本3.22起已被弃用,不应在新编写的代码中使用.
但是,应该使用什么呢?(这是许多已弃用的GdkScreen功能之一.)
具体而言,我如何获得活动窗口的位置和几何?
编辑12/10/16:经过几天的调查,我得出结论,这个问题的答案在developer.gnome.org之外.可能需要直接针对X11,wayland和mir编写单独的代码.
对于它的价值,下面是get_window-areas.c我已经写过探索可以在Gtk中找到的内容而不使用已弃用的函数.似乎没有办法获得窗口标题或活动状态; 所以,我无法复制@ theGtknerd使用不稳定Wnck库的答案的功能.
我只是在学习Gtk,所以我非常感谢你提出的改进意见.我从空窗口代码https://developer.gnome.org/gtk3/stable/gtk-getting-started.html#id-1.2.3.5开始,向其添加了带缓冲区的textview,然后插入了有关几何的信息和每个窗口的位置到文本缓冲区.
gcc `pkg-config --cflags gtk+-3.0` -o get_window-areas get_window-areas.c `pkg-config --libs gtk+-3.0`
Run Code Online (Sandbox Code Playgroud)
get_window-areas.c使用gcc上面的命令在下面编译.
#include <gtk/gtk.h>
static void
activate (GtkApplication* app,
gpointer user_data)
{
GtkWidget *window = NULL;
GtkWidget *text_view;
GtkTextBuffer *buffer;
int x = 0, y = 0, width = 0, height = 0;
char char_x[5], char_y[5], char_width[5], char_height[5];
GdkScreen *screen;
GdkWindow *dwindow;
GList *gl_item = NULL, *gl = NULL;
window = gtk_application_window_new (app);
screen = gtk_window_get_screen (GTK_WINDOW(window));
buffer = gtk_text_buffer_new (NULL);
text_view = gtk_text_view_new_with_buffer (buffer);
gtk_container_add (GTK_CONTAINER (window), text_view);
if(screen != NULL)
{
gl = gdk_screen_get_window_stack(screen);
for (gl_item = g_list_first(gl); gl_item != NULL; gl_item = gl_item->next)
{
dwindow=gl_item->data;
gdk_window_get_root_origin(dwindow, &x, &y);
width = gdk_window_get_width(dwindow);
height = gdk_window_get_height(dwindow);
g_object_unref(dwindow);
snprintf (char_x, 5, "%d", x);
snprintf (char_y, 5, "%d", y);
snprintf (char_width, 5, "%d", width);
snprintf (char_height, 5, "%d", height);
gtk_text_buffer_insert_at_cursor(buffer,char_width,-1);
gtk_text_buffer_insert_at_cursor(buffer,"x", -1);
gtk_text_buffer_insert_at_cursor(buffer,char_height,-1);
gtk_text_buffer_insert_at_cursor(buffer," at (", -1);
gtk_text_buffer_insert_at_cursor(buffer,char_x, -1);
gtk_text_buffer_insert_at_cursor(buffer,",", -1);
gtk_text_buffer_insert_at_cursor(buffer,char_y,-1);
gtk_text_buffer_insert_at_cursor(buffer,")\n", -1);
};
g_list_free (gl);
}
else {gtk_text_buffer_insert_at_cursor(buffer, "Failed to get default screen.\n", -1);}
gtk_widget_show_all (window);
}
int
main (int argc,
char **argv)
{
GtkApplication *app;
int status;
app = gtk_application_new ("com.github.colinkeenan.silentcast", 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;
}
Run Code Online (Sandbox Code Playgroud)
(2017 年 3 月 11 日编辑,通过在打开时关闭显示来消除内存泄漏)
\n\n(编辑 3/6/17 以初始化 get_top_window 中的 s)
\n\n(编辑 12/24 以提供 X11 的完整答案,并标记为正确答案,直到有人找到通用解决方案)。这是我在 github 上重写/重构silentcast 应用程序(之前只是一系列使用 yad 作为 UI 的 bash 脚本)的一部分,尽管我还没有将任何 Gtk 代码放在 github 上。
\n\n我下面的“正确答案”允许您实际获取活动的 GdkWindow、它的几何图形和范围,或者带有子项的活动 X11 窗口及其几何图形。
\n\n正确答案
\n\n(请注意,它仅适用于 X11,因此应包含并针对 gtk/gtkx.h 进行编译,而不是 gtk/gtk.h)
\n\n.h 文件
\n\n/*\n * Filename: SC_X11_get_active_window.h \n * App Name: Silentcast <https://github.com/colinkeenan/silentcast>\n * Copyright \xc2\xa9 2016, 2017 Colin N Keenan <colinnkeenan@gmail.com>\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or\n * (at your option) any later version.\n * \n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Library General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n * \n * Description: defines some custom X11 error messags and exposes 3 functions:\n * SC_get_active_gdkwindow (...), SC_get_geomeotry_for (...), \n * and SC_get_active_windows_and_geometry (...)\n */\n\n#include <gtk/gtkx.h>\n\n#define SC_X11_ERROR0 " \\n"\n#define SC_X11_ERROR1 "Failed to connect to X server.\\n"\n#define SC_X11_ERROR2 "x11 error trying to get focused window\\n"\n#define SC_X11_ERROR3 "X11 reports no focused window\\n"\n#define SC_X11_ERROR4 "X11 error trying to get top window\\n"\n\n#define D_ERR 1\n#define FOCUS_ERR1 2\n#define FOCUS_ERR2 3\n#define TOP_ERR 4\n#define UKN_ERR 5\n\n#define SC_X11_E1 D_ERR\n#define SC_X11_E2 FOCUS_ERR1\n#define SC_X11_E3 FOCUS_ERR2\n#define SC_X11_E4 TOP_ERR\n#define SC_X11_E0 UKN_ERR\n\nunsigned int SC_get_active_X11window (Window *w, Window* *w_children, ssize_t *n);\n\ngboolean SC_get_active_gdkwindow (Window aw, Window *aw_children, ssize_t n, GdkWindow* *gdkwindow);\n\nvoid SC_get_geometry_for (Window aw, Window *aw_children, ssize_t n, int *x, int *y, \n unsigned int *width, unsigned int *height, GdkRectangle *extents, GdkWindow* *gdkwindow); \n\ngboolean SC_get_active_windows_and_geometry (Window *aw, Window* *aw_children, ssize_t *n,\n int *x, int *y, unsigned int *width, unsigned int *height, GdkRectangle *extents, GdkWindow* *gdkwindow); \nRun Code Online (Sandbox Code Playgroud)\n\n.c 文件
\n\n/*\n * Filename: SC_X11_get_active_window.c \n * App Name: Silentcast <https://github.com/colinkeenan/silentcast>\n * Copyright \xc2\xa9 2016 Colin N Keenan <colinnkeenan@gmail.com>\n * \n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or\n * (at your option) any later version.\n * \n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Library General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n * \n * Description: adapted from "get the active window on X window system" \n * https://gist.github.com/kui/2622504\n * to get Gdk geometry of the active window, both the\n * inner window and the extents\n */\n\n\n#include "SC_X11_get_active_window.h"\n\nBool xerror = False;\n\nstatic int handle_error (Display* display, XErrorEvent* error) {\n xerror = True;\n return 1;\n}\n\nstatic int get_focus_window (Display* d, Window *w) {\n int revert_to;\n\n XGetInputFocus (d, w, &revert_to);\n if (xerror) return FOCUS_ERR1; //X error trying to get focused window\n else if (w == None) return FOCUS_ERR2; //no focused window\n else return 0;\n}\n\nstatic int get_top_window (Display* d, Window start, Window *w, Window* *w_children, ssize_t *n) {\n Window parent = start, root = None, *children = NULL;\n *w = start; \n unsigned int nchildren;\n Status s = XQueryTree (d, *w, &root, &parent, &children, &nchildren), s_prev;\n\n /* ultimately trying to get *w and *w_children */\n while (parent != root && !xerror) {\n\n *w = parent; //previous parent\n s_prev = s; //previous status of XQueryTree\n if (s_prev) {\n *w_children = children; //previous children\n *n = nchildren; //previous number of children\n }\n\n s = XQueryTree (d, *w, &root, &parent, &children, &nchildren);\n /* When parent == root, the previous "parent" is the top window.\n * Save the children of the top window too, but XFree all other\n * children.\n */\n if (parent != root) {\n // parent is not root, so previous parent wasn\'t top window, so don\'t need it\'s children\n if (s_prev) XFree (*w_children); \n } else \n if (s) XFree (children); // don\'t keep the children of root either\n }\n if (xerror) return TOP_ERR;\n else return 0;\n}\n\nunsigned int \nSC_get_active_X11window (Window *w, Window* *w_children, ssize_t *n)\n{\n Display* d = NULL;\n unsigned int e = 0;\n\n XSetErrorHandler (handle_error);\n d = XOpenDisplay (NULL); \n if (d == NULL) { \n return D_ERR; \n } else {\n /* set w to the focused window */\n e = get_focus_window (d, w); \n if (e) { //if error\n XCloseDisplay (d);\n return e;\n }\n /* get_top_window will set w to the top focused window (active window) */\n e = get_top_window (d, *w, w, w_children, n); \n if (e) { //if error\n XCloseDisplay (d);\n return e;\n }\n XCloseDisplay(d);\n } \n\n return 0; //no error\n}\n\n/* SC_get_active_gdkwindow (...) tries to match a GdkWindow to one of the passed X11\n * windows (supposed to be the active X11 window and it\'s n children), and returns\n * TRUE if such a match is found, FALSE if not\n */\ngboolean\nSC_get_active_gdkwindow (Window aw, Window *aw_children, ssize_t n, GdkWindow* *gdkwindow) {\n ssize_t i = 0;\n GdkWindow *dwindow = NULL;\n GdkScreen *screen = NULL;\n GList *gl_item = NULL, *gl = NULL;\n gboolean active_window_found = FALSE;\n\n\n screen = gdk_screen_get_default ();\n if (screen != NULL) { \n /* Go through all windows known to Gtk and check XID against active X11 window, aw. */\n gl = gdk_screen_get_window_stack (screen);\n for (gl_item = g_list_first (gl); !active_window_found && gl_item != NULL; gl_item = gl_item->next) { \n\n dwindow = gl_item->data;\n\n if (gdk_x11_window_get_xid (dwindow) == aw) active_window_found = TRUE;\n else for (i = 0; i < n; i++) //aw didn\'t match this dwindow, so check all of aw_children\n if (gdk_x11_window_get_xid (dwindow) == aw_children[i]) active_window_found = TRUE;\n\n if (!active_window_found) g_object_unref (dwindow);\n else *gdkwindow = dwindow;\n } \n g_list_free (gl);\n }\n return active_window_found;\n}\n\n/* SC_get_geometry_for (...) trys to get the Gdk geometry for the GdkWindow\n * matching the passed X11 window with children, getting both the internal\n * window geometry and it\'s extents (title-bar/frame). If can\'t get Gdk info\n * will get the X11 geometry, setting both inner and extents geometry to\n * the same values. \n */\n\nvoid\nSC_get_geometry_for (Window aw, Window *aw_children, ssize_t n, GdkRectangle *win_rect, GdkRectangle *extents, GdkWindow* *dwindow) {\n unsigned int bwidth = 0, depth = 0, width, height;\n int x, y;\n Window root = 0;\n\n if (SC_get_active_gdkwindow (aw, aw_children, n, dwindow)) {\n gdk_window_get_frame_extents (*dwindow, extents); //{top-left corner, width & height} of title-bar/borders\n gdk_window_get_origin(*dwindow, &x, &y); //top-left corner of interior window (not title bar/borders)\n width = gdk_window_get_width (*dwindow); //width of interior window\n height = gdk_window_get_height (*dwindow); //height of interior window\n win_rect->x = x;\n win_rect->y = y;\n win_rect->width = (int) width;\n win_rect->height = (int) height;\n } else {\n fprintf (stderr, "Failed to get GdkWindow. Falling back on X11 geometry of active window, saved as both extents and interior geometry.");\n Display* d = XOpenDisplay (NULL); \n if (d) {\n XGetGeometry (d, aw, &root, &x, &y, &width, &height, &bwidth, &depth);\n XCloseDisplay (d);\n extents->x = x;\n extents->y = y;\n extents->width = (int) width;\n extents->height = (int) height;\n }\n }\n}\n\n/* SC_get_active_windows_and_geometry (...) calls get_active_x11window (...) to get the active X11 window\n * and it\'s children, then calls SC_get_geometry_for (...) to get geometry (hopefully Gdk) that matches\n */\ngboolean\nSC_get_active_windows_and_geometry (Window *aw, Window* *aw_children, ssize_t *n, \n GdkRectangle *win_rect, GdkRectangle *extents, GdkWindow* *dwindow) {\n\n switch (SC_get_active_X11window(aw, aw_children, n)) { get aw, aw_children, and n (number of children)\ncase 0: SC_get_geometry_for (*aw, *aw_children, *n, win_rect, extents, dwindow); return TRUE; \ncase SC_X11_E1: fprintf (stderr, SC_X11_ERROR1); break;\ncase SC_X11_E2: fprintf (stderr, SC_X11_ERROR2); break;\ncase SC_X11_E3: fprintf (stderr, SC_X11_ERROR3); break;\ncase SC_X11_E4: fprintf (stderr, SC_X11_ERROR4); break;\n } \n return FALSE; //failed to get active window due to X11 error\n}\nRun Code Online (Sandbox Code Playgroud)\n\n我之前的答案通常得到正确的几何形状,但不是窗口
\n\n我已经改编了“在 X 窗口系统上获取活动窗口” https://gist.github.com/kui/2622504中的代码,以与问题中的示例配合使用。我把它变成了图书馆。我没有将其标记为正确答案,因为这是我编写的第一个库文件,而且我对 Gtk 也是完全陌生的。我也没有太多编写 C 代码的经验。最后,正确答案应该包括 X11、Wayland 和 MIR 的库。我很高兴看到一个答案,包括我的改进库和缺少的两个库。
\n\n编译如下:
\n\ngcc `pkg-config --cflags gtk+-3.0` -o get_window-areas X11_get_active_window_geometry.c get_window-areas.c `pkg-config --libs gtk+-3.0` -lX11\nRun Code Online (Sandbox Code Playgroud)\n\nX11_get_active_window_geometry.h
#include <X11/Xlib.h>\n\n#define SC_X11_ERROR0 "Uknown error from get_actve_window_geometry.\\n"\n#define SC_X11_ERROR1 "Failed to connect to X server.\\n"\n#define SC_X11_ERROR2 "x11 error trying to get focused window\\n"\n#define SC_X11_ERROR3 "X11 reports no focused window\\n"\n#define SC_X11_ERROR4 "X11 error trying to get top window\\n"\n#define SC_X11_ERROR5 "X11 error trying to get the active-window geometry.\\n"\n\n#define D_ERR 1\n#define FOCUS_ERR1 2\n#define FOCUS_ERR2 3\n#define TOP_ERR 4\n#define GEOM_ERR 5\n\n#define SC_X11_E1 D_ERR\n#define SC_X11_E2 FOCUS_ERR1\n#define SC_X11_E3 FOCUS_ERR2\n#define SC_X11_E4 TOP_ERR\n#define SC_X11_E5 GEOM_ERR\n\nunsigned int get_active_window_geometry (int *x, int *y, unsigned int *width, unsigned int *height); \nRun Code Online (Sandbox Code Playgroud)\n\nX11_get_active_window_geometry.c
#include "X11_get_active_window_geometry.h"\n\nBool xerror = False;\n\nstatic int handle_error (Display* display, XErrorEvent* error) {\n xerror = True;\n return 1;\n}\n\nstatic int get_focus_window (Display* d, Window *w) {\n int revert_to;\n\n XGetInputFocus (d, w, &revert_to);\n if (xerror) return FOCUS_ERR1; //X error trying to get focused window\n else if (w == None) return FOCUS_ERR2; //no focused window\n else return 0;\n}\n\nstatic int get_top_window (Display* d, Window start, Window *w){\n Window parent = start, root = None, *children;\n *w = start; \n unsigned int nchildren;\n Status s;\n\n while (parent != root && !xerror) {\n *w = parent;\n s = XQueryTree (d, *w, &root, &parent, &children, &nchildren);\n\n if (s)\n XFree (children);\n }\n if (xerror) return TOP_ERR;\n else return 0;\n}\n\nunsigned int get_active_window_geometry (int *x, int *y, \n unsigned int *width, unsigned int *height) \n{\n Display* d = NULL;\n Window root, w;\n unsigned int bwidth = 0, depth = 0, e = 0;\n\n XSetErrorHandler (handle_error);\n d = XOpenDisplay (NULL);\n if (d == NULL) { \n return D_ERR; \n } else {\n e = get_focus_window (d,&w); //get focused window w\n if (e) return e;\n e = get_top_window (d, w, &w); //get top focused window w (the active window)\n if (e) return e;\n XGetGeometry (d, w, &root, x, y, width, height, &bwidth, &depth);\n if (xerror) return GEOM_ERR;\n } \n return 0;\n}\nRun Code Online (Sandbox Code Playgroud)\n\nget_active_window.c
#include <gtk/gtk.h>\n#include "X11_get_active_window_geometry.h"\n\nstatic void\nactivate (GtkApplication* app,\n gpointer user_data)\n{\n GtkWidget *window = NULL, *text_view;\n GtkTextBuffer *buffer;\n unsigned int width = 0, height = 0, widtha = 0, heighta = 0, iwidtha = 0, iheighta = 0;\n int x = 0, y = 0, xa = 0, ya = 0, ixa =0, iya = 0;\n GdkRectangle extents= { 0, 0, 0, 0 };\n char char_x[5], char_y[5], char_width[5], char_height[5]; \n GdkScreen *screen;\n GdkWindow *dwindow;\n GList *gl_item = NULL, *gl = NULL;\n\n window = gtk_application_window_new (app);\n screen = gtk_window_get_screen (GTK_WINDOW(window));\n buffer = gtk_text_buffer_new (NULL);\n text_view = gtk_text_view_new_with_buffer (buffer);\n gtk_container_add (GTK_CONTAINER (window), text_view);\n\n#define ADD_TEXT(STRING) gtk_text_buffer_insert_at_cursor (buffer,STRING,-1)\n#define ADD_INT(CHAR_INT,INT) snprintf (CHAR_INT, 5, "%d", INT); ADD_TEXT(CHAR_INT);\n#define ADD_GEOMETRY_TEXT(X,Y,WIDTH,HEIGHT) ADD_INT(char_width, WIDTH); ADD_TEXT("x"); ADD_INT(char_height, HEIGHT); ADD_TEXT(" at ("); ADD_INT(char_x, X); ADD_TEXT(","); ADD_INT(char_y, Y); ADD_TEXT(")\\n");\n\n /* get active window geometry using X11 and handle error, if any*/\n switch (get_active_window_geometry(&xa, &ya, &widtha, &heighta)) { \ncase 0:\n ADD_TEXT("GEOMETRY FOR ACTIVE WINDOW USING X11\\n");\n ADD_GEOMETRY_TEXT(xa, ya, widtha, heighta);\n ADD_TEXT("\\n");\n break;\ncase SC_X11_E1:\n ADD_TEXT(SC_X11_ERROR1);\n break;\ncase SC_X11_E2:\n ADD_TEXT(SC_X11_ERROR2);\n break;\ncase SC_X11_E3:\n ADD_TEXT(SC_X11_ERROR3);\n break;\ncase SC_X11_E4:\n ADD_TEXT(SC_X11_ERROR4);\n break;\ncase SC_X11_E5:\n ADD_TEXT(SC_X11_ERROR5);\n break;\ndefault:\n ADD_TEXT(SC_X11_ERROR0);\n } \n\n /* get window geometry for all windows using Gtk and identify the active one by comparison with X11 result*/\n if (screen != NULL) { \n ADD_TEXT("GEOMETRY FOR ALL WINDOWS USING Gtk:\\n\\n");\n gl = gdk_screen_get_window_stack (screen);\n for (gl_item = g_list_first (gl); gl_item != NULL; gl_item = gl_item->next) { \n dwindow=gl_item->data;\n gdk_window_get_frame_extents (dwindow, &extents); //{top-left corner, width & height} of title-bar/borders\n ADD_TEXT("Entirety of Window: ");\n ADD_GEOMETRY_TEXT(extents.x, extents.y, extents.width, extents.height);\n gdk_window_get_origin(dwindow, &x, &y); //top-left corner of interior window (not title bar/borders)\n width = gdk_window_get_width (dwindow); //width of interior window\n height = gdk_window_get_height (dwindow); //height of interior window\n ADD_TEXT("Interior of Window: ");\n ADD_GEOMETRY_TEXT(x, y, width, height);\n ADD_TEXT("\\n");\n /*If extents matches active window geometry, save interior window geometry */\n if (extents.x == xa && extents.y == ya && extents.width == widtha && extents.height == heighta) {\n ixa = x; iya = y; iwidtha = width; iheighta = height;\n }\n g_object_unref (dwindow);\n }; \n g_list_free (gl);\n ADD_TEXT("MATCHING THE ACTIVE WINDOW REPORTED BY X11 WITH THE GTK WINDOW GEOMETRIES:\\n");\n ADD_TEXT("Entirety of Active Window: ");\n ADD_GEOMETRY_TEXT(xa, ya, widtha, heighta);\n ADD_TEXT("Interior of Active Window: ");\n ADD_GEOMETRY_TEXT(ixa, iya, iwidtha, iheighta);\n } else {\n ADD_TEXT("Failed to get default screen.\\n");\n }\n\n gtk_widget_show_all (window);\n}\n\nint\nmain (int argc,\n char **argv)\n{\n GtkApplication *app;\n int status;\n\n app = gtk_application_new ("com.github.colinkeenan.silentcast", G_APPLICATION_FLAGS_NONE);\n g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);\n status = g_application_run (G_APPLICATION (app), argc, argv);\n g_object_unref (app);\n\n return status;\n}\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
950 次 |
| 最近记录: |