это подпроект гораздо более крупного исследовательского проекта. Я пытаюсь делать скриншоты активного окна (браузера) каждые 100 мс, которые затем сохраняются в памяти для обработки OpenCV. По аналогичному вопросу я нашел решение сделать снимок экрана, и сейчас я играю с кодом, чтобы посмотреть, смогу ли я его использовать. Следующий фрагмент, кажется, работает либо при создании всего снимка экрана рабочего стола, либо конкретного снимка экрана Windows, но он не работает для окон GTK. Я пытался сделать скриншот Iceweasel & Наутилус на Debian Squeeze, и он просто не работает. Я полный нуб в 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 (libxdo в Debian):
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, я действительно надеюсь, что это может помочь кому-то застрять в этом, поскольку, кажется, очень мало сообщений об этом.
Других решений пока нет …