X11 Xlib截屏代码所遇问题及初步分析

614 阅读2分钟

本文已参与 [新人创作礼] 活动,一起开启掘金创作之路。​

综合了两篇博客中的例程并做一定修改,得到了基于X11 Xlib的截屏代码。

两篇博客链接分别如下:

X11 截图与鼠标事件-SkyMei777-ChinaUnix博客

xlib实现截图报错-编程语言-CSDN问答

C代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>

int main(int argc, char *argv[])
{
	Display *display = XOpenDisplay(NULL);
	if(!display)
	{
		printf("XOpenDisplay failed\n");
		return -1;
	}

	int screen_num = DefaultScreen(display);
	printf("default screen_num is: %d\n", screen_num);

	int screen_width = DisplayWidth(display, screen_num);
	int screen_height = DisplayHeight(display, screen_num);
	printf("screen_width: %d, screen_height: %d\n", screen_width, screen_height);

	Window root_win = RootWindow(display, screen_num);
	if(!root_win)
	{
		printf("can not get root window\n");
		return -1;
	}

	Window disp_win = XCreateSimpleWindow(display, root_win, 0, 0, screen_width, screen_height, 1, 0, 0) ;
	if(!disp_win)
	{
		printf("can not get snapshot display window\n");
		return -1;
	}

	XMapWindow(display, disp_win);

	XImage *img = XGetImage(display, root_win, 0, 0, screen_width, screen_height, ~0, ZPixmap);	

	XPutImage(display, disp_win, DefaultGC(display, screen_num), img, 0, 0, 0, 0, screen_width, screen_height);

	char c = getchar();

	//XDestroyImage(img);
	XCloseDisplay(display);

	printf("screen_snapshot finished\n");

	return 0;
}

Makefile:

all:
	gcc ./screen_snapshot.c -o screen_snapshot -lX11

第一次编译出现以下警告:

$ make
gcc ./screen_snapshot.c -o screen_snapshot -lX11
./screen_snapshot.c: In function ‘main’:
./screen_snapshot.c:41:9: warning: implicit declaration of function ‘XDestroyImage’; did you mean ‘XDestroyIC’? [-Wimplicit-function-declaration]
   41 |         XDestroyImage(img);
      |         ^~~~~~~~~~~~~
      |         XDestroyIC

查看/usr/include/X11/Xlib.h文件,确实并未发现有XDestroyImage相关的定义,可能是以前版本有此函数,后来被废弃了。在代码中注释掉这一句,再次编译,这次可以正常编译通过了。

编译通过后运行生成的screen_snapshot程序,如下所示:

$ ./screen_snapshot 
default screen_num is: 0
screen_width: 1920, screen_height: 1080
X Error of failed request:  BadMatch (invalid parameter attributes)
  Major opcode of failed request:  73 (X_GetImage)
  Serial number of failed request:  9
  Current serial number in output stream:  9

可以看到出现了错误。实际上这个错误就是上边第2篇参考文章链接中博主“编程小海浪”遇到的问题,截图如下:

在网上搜索解决方法,发现并不只是这个代码遇到的问题,许多人说xrandr也会报这个错。解法也提了还不少,如:手动修改分辨率、修改显卡设置等。关于这些方法,我没有一一测试,只说一下我这里的情况。

我的电脑中安装的是Ubuntu 22.04,运行程序出现的问题。将同样的程序放到另外一台基于LFS的电脑系统中,运行则并没有问题,至少不报以上错误还能截屏(屏幕内容有时不正确是另外的问题)。

在此给出个人的初步分析和判断,希望哪位遇到过此问题、有经验的同仁予以关注、回复,也可以大家一起讨论:

  • 可能与桌面是XOrg和wayland有关

Ubuntu下的桌面环境是wayland,如下所示:

$ echo $XDG_SESSION_TYPE 
wayland

正常电脑的桌面环境是x11,如下所示:

$ echo $XDG_SESSION_TYPE 
x11

  • 可能与分辨率及显卡设置有关
  • 可能与xorg设置有关
  • 可能与内核驱动有关

具体是哪里的问题,只能随着进一步的实验测试再进行详细分析了。