c++ - GTK 窗口的事件窗口的 X11 屏幕截图失败

标签 c++ c gtk x11 xlib

这是一个更大的研究项目的子项目。我试图每 100 毫秒截取一个事件窗口(浏览器)的屏幕截图,然后将其存储在内存中以供 OpenCV 处理。我从类似的问题中找到了截屏的解决方案,目前我正在玩代码以查看是否可以使用它。以下代码片段似乎在获取整个桌面屏幕截图或特定窗口屏幕截图时有效,但不适用于 GTK 窗口。我尝试在 Debian Squeeze 上截取 Iceweasel & Nautilus 的屏幕截图,但根本行不通。我完全是 X11 的菜鸟,不知道如何检查错误,或者我是否缺少 GTK 的某些东西,因为这似乎适用于 QT 窗口。

typedef int (*handler)(Display *, XErrorEvent *);

int handleX11Error(Display *d, XErrorEvent *er)
{
   std::cout << "X11 Error: " << er->error_code << std::endl;
}

int main()
{
    std::cout << "Sleeping 5 seconds" << std::endl;
   // we may need to sleep if we want to focus another window.
   sleep(5); 
   std::cout << "taking screenshot" << std::endl;

   Display *display = XOpenDisplay(NULL);
   //Window root = DefaultRootWindow(display);
   XWindowAttributes gwa;
   int revert = RevertToNone;
   Window active;
   XErrorEvent *error;
   handler myHandler = &handleX11Error;
   XSetErrorHandler(myHandler);

   // X11 - Get Window that has focus
   XGetInputFocus(display,&active,&revert);

   //XGetWindowAttributes(display, root, &gwa);
   if (!XGetWindowAttributes(display, active, &gwa))
     std::cout << "XGetWindowAttributes failed" << std::endl;

   int width = gwa.width;
   int height = gwa.height;

   //XImage *image = XGetImage(display,root, 0,0 , width,height,AllPlanes, ZPixmap);
   XImage *image = XGetImage(display,active, 0,0 , width,height,XAllPlanes(), ZPixmap);

   unsigned char *array = new unsigned char[width * height * 3];
   CImg<unsigned char> pic(array,width,height,1,3);

   for (int x = 0; x < width; x++){
      for (int y = 0; y < height ; y++){
     pic(x,y,0) = (XGetPixel(image,x,y) & image->red_mask ) >> 16;
     pic(x,y,1) = (XGetPixel(image,x,y) & image->green_mask ) >> 8;
     pic(x,y,2) = XGetPixel(image,x,y) & image->blue_mask;
      }
   }
   delete[] array;
   pic.save_png("blah.png");
   std::cout <<  "Finished" << std::endl;
   return 0;
}

以上代码适用于完整的桌面屏幕截图或 QT。我没有收到任何错误(不知道我是否正确处理了它们)。只是几个字节的空白图片,这让我认为 X 函数之一失败(XGetInputFocus、XGetWindowAttributes、XGetImage),我打赌 XGetFocus 无法正常工作。 我缺少什么,或者有其他选择吗? 请注意,如果有任何重要意义,我正在运行 KDE (4.4.5)。

更新:

我尝试使用 Qt4 截取屏幕截图,虽然它工作正常,但在尝试从 X11 获取焦点窗口时遇到同样的问题:

int main(int argc, char **argv)
{
    sleep(5);
    Display *display = XOpenDisplay(NULL);
    int revert = RevertToNone;
    Window active;
    XGetInputFocus(display,&active,&revert);
    QApplication app(argc, argv);    
    QPixmap pixmap = QPixmap::grabWindow(active);
    pixmap.save("test.png","PNG");
    QPushButton quit("Quit");
    quit.resize(75, 30);
    quit.setFont(QFont("Times", 18, QFont::Bold));
    QObject::connect(&quit, SIGNAL(clicked()), &app, SLOT(quit()));
    quit.show();
    return app.exec();
}

因此,我确信是 XGetInputFocus() 以某种方式失败了。

最佳答案

由于我还没有得到任何答案,而且我花了一整天的大部分时间来寻找解决方案,所以我想我应该分享一下我是如何成功实现这一目标的。 系统是 Debian Squeeze,运行 KDE 4.4.5。 显然,KDE 和 GTK 应用程序不能很好地相互配合。引用 stackoverflow 和互联网上其他帖子的人的话,非 kde 应用程序可能不支持 _NET_WM_STATE,或者它可能是其他东西,我真的不知道。但事实是,我尝试的 GTK 应用程序无法使用所有 Qt4 应用程序都可以使用的代码片段,这暗示了与某种形式的报告相关的问题。在网上找到的一些罕见的(我的意思是罕见的)解决方案可能会遍历 X11 窗口树以找到事件窗口,但这对我来说太复杂了,而且我阅读了一些没有获得成功结果的人的帖子。 我使用 xdo(Debian 上的 libxdo)得出的结果(这是在网上找到的一些片段):

   Display *display = XOpenDisplay(NULL);
   Window active;
   XWindowAttributes gwa;

   // Use xdo to find the active window - care on the display !
   xdo_t* xdocontext = xdo_new(0);
   xdo_window_get_active(xdocontext, &active);
   if(active){
      XGetWindowAttributes(display, active, &gwa);
      XImage *image = XGetImage(display,active, 0,0 , gwa.width,gwa.height,XAllPlanes(), ZPixmap);
      unsigned char *array = new unsigned char[gwa.width * gwa.height * 3];
      CImg<unsigned char> pic(array,gwa.width,gwa.height,1,3);

      for (int x = 0; x < gwa.width; x++){
         for (int y = 0; y < gwa.height ; y++){
             pic(x,y,0) = (XGetPixel(image,x,y) & image->red_mask ) >> 16;
             pic(x,y,1) = (XGetPixel(image,x,y) & image->green_mask ) >> 8;
             pic(x,y,2) = XGetPixel(image,x,y) & image->blue_mask;
         }
      }
      delete[] array;
      pic.save_png("blah.png");
   } else std::cout << "xdo failed to get active window" << std::endl;

上面的内容适用于 GTK 和 KDE 应用程序,我真的希望它可以帮助那些坚持这一点的人,因为这方面的帖子似乎很少。

关于c++ - GTK 窗口的事件窗口的 X11 屏幕截图失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13647039/

相关文章:

c++ - 使用 Boehm GC 时 C++ 中内存泄漏的原因

c - switch 或 if else block 内的字符串赋值

python - 如何编写扩展的 gtk.CellRendererText() 以在文本旁边显示图像

Python/Glade/PyGTK - Glade 标签中的下载百分比

c++ - CMake 将依赖项复制到可执行输出路径

c++ - 如果用户输入无效则循环

c++ - std::sort 中用 lambda 函数指定的比较函数是否返回 bool 类型?

c - 填充文件 ASCII 值

c - Printf 和 sleep inside for 循环?

c - 加载 gtk 关于对话框时如何避免断言失败?