'gdk_screen_get_active_window ()' is deprecated since Gtk + version 3.22

According to https://developer.gnome.org/gdk3/stable/GdkScreen.html#gdk-screen-get-active-window ,

gdk_screen_get_active_window is deprecated since version 3.22 and should not be used in newly written code.

But what should be used instead? (This is one of the many deprecated features of GdkScreen.)

To be specific, how would I get the location and geometry of the active window?

Edit 12/10/16: After a couple of days studying this, I came to the conclusion that the answer to this question is outside of developer.gnome.org. Perhaps separate code needs to be written directly, focusing on X11, wayland and mir.

For what it's worth, get_window-areas.c , which I wrote, exploring what can be found in Gtk without using obsolete functions. There seems to be no way to get window headers or an active state; so I could not duplicate the functionality of @theGtknerd's answer, which uses unstable Wnck libraries.

I'm just learning Gtk, so I appreciate any comments to improve this. I started with a blank window code https://developer.gnome.org/gtk3/stable/gtk-getting-started.html#id-1.2.3.5 , added a text view with a buffer to it, and then pasted in the geometry and location information each window into a text buffer.

 gcc `pkg-config --cflags gtk+-3.0` -o get_window-areas get_window-areas.c `pkg-config --libs gtk+-3.0` 

Compile get_window-areas.c below using the gcc command above.

 #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; } 
+5
source share
2 answers

(edit 3/11/17 to eliminate memory leaks when closing the display each time you open)

(edit 3/6/17 to initialize s in get_top_window)

(edit 12/24 to get the full answer for X11 and mark it as the correct answer until someone has a common solution). This is part of my work of rewriting / refactoring my silentcast application (previously just a series of bash scripts using yad for the UI) on github, although I haven't put any of this Gtk code on github yet.

My “Correct Answer” below allows you to actually get the active GdkWindow, its geometry and extents, or the active X11 window with children and geometry.

Correct answer

(note that it only applies to X11, so it should include and compile in gtk / gtkx.h, not gtk / gtk.h)

.h file

 /* * Filename: SC_X11_get_active_window.h * App Name: Silentcast <https://github.com/colinkeenan/silentcast> * Copyright © 2016, 2017 Colin N Keenan < colinnkeenan@gmail.com > * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Description: defines some custom X11 error messags and exposes 3 functions: * SC_get_active_gdkwindow (...), SC_get_geomeotry_for (...), * and SC_get_active_windows_and_geometry (...) */ #include <gtk/gtkx.h> #define SC_X11_ERROR0 " \n" #define SC_X11_ERROR1 "Failed to connect to X server.\n" #define SC_X11_ERROR2 "x11 error trying to get focused window\n" #define SC_X11_ERROR3 "X11 reports no focused window\n" #define SC_X11_ERROR4 "X11 error trying to get top window\n" #define D_ERR 1 #define FOCUS_ERR1 2 #define FOCUS_ERR2 3 #define TOP_ERR 4 #define UKN_ERR 5 #define SC_X11_E1 D_ERR #define SC_X11_E2 FOCUS_ERR1 #define SC_X11_E3 FOCUS_ERR2 #define SC_X11_E4 TOP_ERR #define SC_X11_E0 UKN_ERR unsigned int SC_get_active_X11window (Window *w, Window* *w_children, ssize_t *n); gboolean SC_get_active_gdkwindow (Window aw, Window *aw_children, ssize_t n, GdkWindow* *gdkwindow); void SC_get_geometry_for (Window aw, Window *aw_children, ssize_t n, int *x, int *y, unsigned int *width, unsigned int *height, GdkRectangle *extents, GdkWindow* *gdkwindow); gboolean SC_get_active_windows_and_geometry (Window *aw, Window* *aw_children, ssize_t *n, int *x, int *y, unsigned int *width, unsigned int *height, GdkRectangle *extents, GdkWindow* *gdkwindow); 

.c file

 /* * Filename: SC_X11_get_active_window.c * App Name: Silentcast <https://github.com/colinkeenan/silentcast> * Copyright © 2016 Colin N Keenan < colinnkeenan@gmail.com > * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Description: adapted from "get the active window on X window system" * https://gist.github.com/kui/2622504 * to get Gdk geometry of the active window, both the * inner window and the extents */ #include "SC_X11_get_active_window.h" Bool xerror = False; static int handle_error (Display* display, XErrorEvent* error) { xerror = True; return 1; } static int get_focus_window (Display* d, Window *w) { int revert_to; XGetInputFocus (d, w, &revert_to); if (xerror) return FOCUS_ERR1; //X error trying to get focused window else if (w == None) return FOCUS_ERR2; //no focused window else return 0; } static int get_top_window (Display* d, Window start, Window *w, Window* *w_children, ssize_t *n) { Window parent = start, root = None, *children = NULL; *w = start; unsigned int nchildren; Status s = XQueryTree (d, *w, &root, &parent, &children, &nchildren), s_prev; /* ultimately trying to get *w and *w_children */ while (parent != root && !xerror) { *w = parent; //previous parent s_prev = s; //previous status of XQueryTree if (s_prev) { *w_children = children; //previous children *n = nchildren; //previous number of children } s = XQueryTree (d, *w, &root, &parent, &children, &nchildren); /* When parent == root, the previous "parent" is the top window. * Save the children of the top window too, but XFree all other * children. */ if (parent != root) { // parent is not root, so previous parent wasn't top window, so don't need it children if (s_prev) XFree (*w_children); } else if (s) XFree (children); // don't keep the children of root either } if (xerror) return TOP_ERR; else return 0; } unsigned int SC_get_active_X11window (Window *w, Window* *w_children, ssize_t *n) { Display* d = NULL; unsigned int e = 0; XSetErrorHandler (handle_error); d = XOpenDisplay (NULL); if (d == NULL) { return D_ERR; } else { /* set w to the focused window */ e = get_focus_window (d, w); if (e) { //if error XCloseDisplay (d); return e; } /* get_top_window will set w to the top focused window (active window) */ e = get_top_window (d, *w, w, w_children, n); if (e) { //if error XCloseDisplay (d); return e; } XCloseDisplay(d); } return 0; //no error } /* SC_get_active_gdkwindow (...) tries to match a GdkWindow to one of the passed X11 * windows (supposed to be the active X11 window and it n children), and returns * TRUE if such a match is found, FALSE if not */ gboolean SC_get_active_gdkwindow (Window aw, Window *aw_children, ssize_t n, GdkWindow* *gdkwindow) { ssize_t i = 0; GdkWindow *dwindow = NULL; GdkScreen *screen = NULL; GList *gl_item = NULL, *gl = NULL; gboolean active_window_found = FALSE; screen = gdk_screen_get_default (); if (screen != NULL) { /* Go through all windows known to Gtk and check XID against active X11 window, aw. */ gl = gdk_screen_get_window_stack (screen); for (gl_item = g_list_first (gl); !active_window_found && gl_item != NULL; gl_item = gl_item->next) { dwindow = gl_item->data; if (gdk_x11_window_get_xid (dwindow) == aw) active_window_found = TRUE; else for (i = 0; i < n; i++) //aw didn't match this dwindow, so check all of aw_children if (gdk_x11_window_get_xid (dwindow) == aw_children[i]) active_window_found = TRUE; if (!active_window_found) g_object_unref (dwindow); else *gdkwindow = dwindow; } g_list_free (gl); } return active_window_found; } /* SC_get_geometry_for (...) trys to get the Gdk geometry for the GdkWindow * matching the passed X11 window with children, getting both the internal * window geometry and it extents (title-bar/frame). If can't get Gdk info * will get the X11 geometry, setting both inner and extents geometry to * the same values. */ void SC_get_geometry_for (Window aw, Window *aw_children, ssize_t n, GdkRectangle *win_rect, GdkRectangle *extents, GdkWindow* *dwindow) { unsigned int bwidth = 0, depth = 0, width, height; int x, y; Window root = 0; if (SC_get_active_gdkwindow (aw, aw_children, n, dwindow)) { gdk_window_get_frame_extents (*dwindow, extents); //{top-left corner, width & height} of title-bar/borders gdk_window_get_origin(*dwindow, &x, &y); //top-left corner of interior window (not title bar/borders) width = gdk_window_get_width (*dwindow); //width of interior window height = gdk_window_get_height (*dwindow); //height of interior window win_rect->x = x; win_rect->y = y; win_rect->width = (int) width; win_rect->height = (int) height; } else { fprintf (stderr, "Failed to get GdkWindow. Falling back on X11 geometry of active window, saved as both extents and interior geometry."); Display* d = XOpenDisplay (NULL); if (d) { XGetGeometry (d, aw, &root, &x, &y, &width, &height, &bwidth, &depth); XCloseDisplay (d); extents->x = x; extents->y = y; extents->width = (int) width; extents->height = (int) height; } } } /* SC_get_active_windows_and_geometry (...) calls get_active_x11window (...) to get the active X11 window * and it children, then calls SC_get_geometry_for (...) to get geometry (hopefully Gdk) that matches */ gboolean SC_get_active_windows_and_geometry (Window *aw, Window* *aw_children, ssize_t *n, GdkRectangle *win_rect, GdkRectangle *extents, GdkWindow* *dwindow) { switch (SC_get_active_X11window(aw, aw_children, n)) { get aw, aw_children, and n (number of children) case 0: SC_get_geometry_for (*aw, *aw_children, *n, win_rect, extents, dwindow); return TRUE; case SC_X11_E1: fprintf (stderr, SC_X11_ERROR1); break; case SC_X11_E2: fprintf (stderr, SC_X11_ERROR2); break; case SC_X11_E3: fprintf (stderr, SC_X11_ERROR3); break; case SC_X11_E4: fprintf (stderr, SC_X11_ERROR4); break; } return FALSE; //failed to get active window due to X11 error } 

My previous answer, which usually got the correct geometry, but not a window

I adapted the code from "get active window in windows system X" https://gist.github.com/kui/2622504 to work with my example in the question. I turned it into a library. I don’t think this is the right answer, because this is the first library file I have ever written, and I am completely new to Gtk. I also don't have much experience writing C code. Finally, the correct answer should include libraries for X11, Wayland and MIR. I would be glad to see the answer, including my library with improvements + two missing libraries.

Compile below:

 gcc `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 

X11_get_active_window_geometry.h

 #include <X11/Xlib.h> #define SC_X11_ERROR0 "Uknown error from get_actve_window_geometry.\n" #define SC_X11_ERROR1 "Failed to connect to X server.\n" #define SC_X11_ERROR2 "x11 error trying to get focused window\n" #define SC_X11_ERROR3 "X11 reports no focused window\n" #define SC_X11_ERROR4 "X11 error trying to get top window\n" #define SC_X11_ERROR5 "X11 error trying to get the active-window geometry.\n" #define D_ERR 1 #define FOCUS_ERR1 2 #define FOCUS_ERR2 3 #define TOP_ERR 4 #define GEOM_ERR 5 #define SC_X11_E1 D_ERR #define SC_X11_E2 FOCUS_ERR1 #define SC_X11_E3 FOCUS_ERR2 #define SC_X11_E4 TOP_ERR #define SC_X11_E5 GEOM_ERR unsigned int get_active_window_geometry (int *x, int *y, unsigned int *width, unsigned int *height); 

X11_get_active_window_geometry.c

 #include "X11_get_active_window_geometry.h" Bool xerror = False; static int handle_error (Display* display, XErrorEvent* error) { xerror = True; return 1; } static int get_focus_window (Display* d, Window *w) { int revert_to; XGetInputFocus (d, w, &revert_to); if (xerror) return FOCUS_ERR1; //X error trying to get focused window else if (w == None) return FOCUS_ERR2; //no focused window else return 0; } static int get_top_window (Display* d, Window start, Window *w){ Window parent = start, root = None, *children; *w = start; unsigned int nchildren; Status s; while (parent != root && !xerror) { *w = parent; s = XQueryTree (d, *w, &root, &parent, &children, &nchildren); if (s) XFree (children); } if (xerror) return TOP_ERR; else return 0; } unsigned int get_active_window_geometry (int *x, int *y, unsigned int *width, unsigned int *height) { Display* d = NULL; Window root, w; unsigned int bwidth = 0, depth = 0, e = 0; XSetErrorHandler (handle_error); d = XOpenDisplay (NULL); if (d == NULL) { return D_ERR; } else { e = get_focus_window (d,&w); //get focused window w if (e) return e; e = get_top_window (d, w, &w); //get top focused window w (the active window) if (e) return e; XGetGeometry (d, w, &root, x, y, width, height, &bwidth, &depth); if (xerror) return GEOM_ERR; } return 0; } 

get_active_window.c

 #include <gtk/gtk.h> #include "X11_get_active_window_geometry.h" static void activate (GtkApplication* app, gpointer user_data) { GtkWidget *window = NULL, *text_view; GtkTextBuffer *buffer; unsigned int width = 0, height = 0, widtha = 0, heighta = 0, iwidtha = 0, iheighta = 0; int x = 0, y = 0, xa = 0, ya = 0, ixa =0, iya = 0; GdkRectangle extents= { 0, 0, 0, 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); #define ADD_TEXT(STRING) gtk_text_buffer_insert_at_cursor (buffer,STRING,-1) #define ADD_INT(CHAR_INT,INT) snprintf (CHAR_INT, 5, "%d", INT); ADD_TEXT(CHAR_INT); #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"); /* get active window geometry using X11 and handle error, if any*/ switch (get_active_window_geometry(&xa, &ya, &widtha, &heighta)) { case 0: ADD_TEXT("GEOMETRY FOR ACTIVE WINDOW USING X11\n"); ADD_GEOMETRY_TEXT(xa, ya, widtha, heighta); ADD_TEXT("\n"); break; case SC_X11_E1: ADD_TEXT(SC_X11_ERROR1); break; case SC_X11_E2: ADD_TEXT(SC_X11_ERROR2); break; case SC_X11_E3: ADD_TEXT(SC_X11_ERROR3); break; case SC_X11_E4: ADD_TEXT(SC_X11_ERROR4); break; case SC_X11_E5: ADD_TEXT(SC_X11_ERROR5); break; default: ADD_TEXT(SC_X11_ERROR0); } /* get window geometry for all windows using Gtk and identify the active one by comparison with X11 result*/ if (screen != NULL) { ADD_TEXT("GEOMETRY FOR ALL WINDOWS USING Gtk:\n\n"); 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_frame_extents (dwindow, &extents); //{top-left corner, width & height} of title-bar/borders ADD_TEXT("Entirety of Window: "); ADD_GEOMETRY_TEXT(extents.x, extents.y, extents.width, extents.height); gdk_window_get_origin(dwindow, &x, &y); //top-left corner of interior window (not title bar/borders) width = gdk_window_get_width (dwindow); //width of interior window height = gdk_window_get_height (dwindow); //height of interior window ADD_TEXT("Interior of Window: "); ADD_GEOMETRY_TEXT(x, y, width, height); ADD_TEXT("\n"); /*If extents matches active window geometry, save interior window geometry */ if (extents.x == xa && extents.y == ya && extents.width == widtha && extents.height == heighta) { ixa = x; iya = y; iwidtha = width; iheighta = height; } g_object_unref (dwindow); }; g_list_free (gl); ADD_TEXT("MATCHING THE ACTIVE WINDOW REPORTED BY X11 WITH THE GTK WINDOW GEOMETRIES:\n"); ADD_TEXT("Entirety of Active Window: "); ADD_GEOMETRY_TEXT(xa, ya, widtha, heighta); ADD_TEXT("Interior of Active Window: "); ADD_GEOMETRY_TEXT(ixa, iya, iwidtha, iheighta); } else { ADD_TEXT("Failed to get default screen.\n"); } 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; } 
+2
source

Here is the Python code that gets the active window and prints its geometry.

 #!/usr/bin/python import gi gi.require_version('Wnck', '3.0') from gi.repository import Wnck screen = Wnck.Screen.get_default() screen.force_update() # recommended per Wnck documentation # loop all windows for window in screen.get_windows(): if window.is_active() == True: print (window.get_geometry()) window_name = window.get_name() print (window_name) # clean up Wnck (saves resources, check documentation) window = None screen = None Wnck.shutdown() 

Documentation https://developer.gnome.org/libwnck/stable/WnckWindow.html .

Edit: I'm trying to compile C with which I:

 gcc `pkg-config --cflags --libs libwnck-3.0` -o wnck wnck.c 

and I get the error:

 /usr/include/libwnck-3.0/libwnck/window.h:30:2: error: #error "libwnck should only be used if you understand that it subject to frequent change, and is not supported as a fixed API/ABI or as part of the platform" 

There is a workaround, but I'm not sure if Wnck is a good replacement for GdkScreen. I really don't know what to tell you at this moment.

+2
source

Source: https://habr.com/ru/post/1260950/


All Articles