加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > Windows > 正文

gtk3 – 自gtk版本3.22起不推荐使用’gdk_screen_get_active_win

发布时间:2020-12-14 01:54:20 所属栏目:Windows 来源:网络整理
导读:根据 https://developer.gnome.org/gdk3/stable/GdkScreen.html#gdk-screen-get-active-window, gdk_screen_get_active_window has been deprecated since version 3.22 and should not be used in newly-written code. 但是,应该使用什么呢? (这是许多已弃
根据 https://developer.gnome.org/gdk3/stable/GdkScreen.html#gdk-screen-get-active-window,

gdk_screen_get_active_window has been deprecated since version 3.22 and should not be used in newly-written code.

但是,应该使用什么呢? (这是许多已弃用的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`

使用上面的gcc命令编译下面的get_window-areas.c.

#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,y);
        snprintf (char_width,width);
        snprintf (char_height,height);
        gtk_text_buffer_insert_at_cursor(buffer,char_width,-1);
        gtk_text_buffer_insert_at_cursor(buffer,"x",char_height," at (",char_x,",char_y,")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;
}

解决方法

(编辑3/11/17以通过在打开时关闭显示来消除内存泄漏)

(编辑3/6/17以在get_top_window中初始化s)

(编辑12/24以提供X11的完整答案,并标记为正确答案,直到某人有一般解决方案).这是我在github上重写/重构我的silentcast应用程序(之前只是使用yad for UI的一系列bash脚本)的一部分,尽管我还没有在github上放置任何这个Gtk代码.

我下面的“正确答案”允许你实际获得有效的GdkWindow,它的几何和几何.范围,或带有子项的活动X11窗口,以及它的几何.

正确答案

(请注意,它仅适用于X11,因此应包含并编译gtk / gtkx.h,而不是gtk / gtk.h)

.h文件

/*
 *  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 windown"
#define SC_X11_ERROR3 "X11 reports no focused windown"
#define SC_X11_ERROR4 "X11 error trying to get top windown"

#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,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,GdkWindow* *gdkwindow);

.c文件

/*
 *  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,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,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,&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's 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,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_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's n children),and returns
 * TRUE if such a match is found,FALSE if not
 */
gboolean
SC_get_active_gdkwindow (Window aw,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's 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,GdkRectangle *win_rect,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,&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,&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's children,then calls SC_get_geometry_for (...) to get geometry (hopefully Gdk) that matches
 */
gboolean
SC_get_active_windows_and_geometry (Window *aw,GdkWindow* *dwindow) {

  switch (SC_get_active_X11window(aw,n)) {  get aw,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
}

我以前的答案通常得到正确的几何,但不是窗口

我修改了“在X窗口系统上获取活动窗口”https://gist.github.com/kui/2622504的代码,以便在问题中使用我的示例.我把它变成了一个图书馆.我没有将此标记为正确的答案,因为这是我写过的第一个库文件,我也是Gtk的新手.我也没有太多编写C代码的经验.最后,正确答案应包括X11,Wayland和MIR的库.我很高兴看到一个答案,包括我的图书馆,改进了缺少的两个库.

编译如下:

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 windown"
#define SC_X11_ERROR3 "X11 reports no focused windown"
#define SC_X11_ERROR4 "X11 error trying to get top windown"
#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,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,&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 *w){
    Window parent = start,*children;
  *w = start; 
  unsigned int nchildren;
  Status s;

  while (parent != root && !xerror) {
    *w = parent;
    s = XQueryTree (d,&nchildren);

    if (s)
      XFree (children);
  }
    if (xerror) return TOP_ERR;
    else return 0;
}

unsigned int get_active_window_geometry (int *x,unsigned int *height) 
{
    Display* d = NULL;
    Window root,w;
  unsigned int bwidth = 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); //get top focused window w (the active window)
        if (e) return e;
        XGetGeometry (d,x,y,height,&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,xa = 0,ya = 0,ixa =0,iya = 0;
  GdkRectangle extents= { 0,0 };
    char char_x[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,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 X11n");
            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:nn");
        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,&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,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,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,argv);
  g_object_unref (app);

  return status;
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读