簡體   English   中英

GTK窗口的活動窗口的X11屏幕截圖失敗

[英]X11 screenshot of active window fails for GTK windows

這是一個更大的研究項目的子項目。 我試圖每隔100ms拍攝一個活動窗口(瀏覽器)的屏幕截圖,然后將其存儲在內存中以供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應用程序,我真的希望它可以幫助有人堅持這一點,因為似乎有很少的帖子。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM