在调整大小时,如何防止Cairo/X11闪烁?
我想用Cairo做一个GUI应用,但每次把主窗口往内缩小时,背景颜色会闪现一帧。有一个类似的问题,关于这个的 如何避免Cairo绘制的Xlib表面闪烁?,但那个唯一的答案(只是改变背景颜色)其实并不能解决问题。
下面有一个简单的例子来说明我的观点:
#include <threads.h>
#include <X11/Xlib.h>
#include <cairo/cairo.h>
#include <cairo/cairo-xlib.h>
constexpr int start_width = 400;
constexpr int start_height = 400;
_Atomic bool have_been_killed = false;
Display *_Atomic display;
cairo_surface_t *_Atomic main_surface;
int guiThread(void *const data);
int main(int, char *[]) {
display = XOpenDisplay(nullptr);
if (!display) {
return 1;
}
const Window root_window = XDefaultRootWindow(display);
if (!root_window) {
return 1;
}
const Window main_window = XCreateWindow(
display, root_window,
100, 100, start_width, start_height, 0,
CopyFromParent, CopyFromParent, CopyFromParent,
CWBackPixel | CWEventMask,
&(XSetWindowAttributes){
.background_pixel = 0xFF1E1E1E,
.event_mask = StructureNotifyMask,
}
);
XWindowAttributes main_window_attributes;
if (!XGetWindowAttributes(display, main_window, &main_window_attributes)) {
return 1;
}
Atom WM_DELETE_WINDOW = XInternAtom(display, "WM_DELETE_WINDOW", true);
if(!XSetWMProtocols(display, main_window, &WM_DELETE_WINDOW, 1)) {
return 1;
}
main_surface = cairo_xlib_surface_create(display, main_window, main_window_attributes.visual, start_width, start_height);
cairo_t *cairo = cairo_create(main_surface);
if (!cairo) {
return 1;
}
thrd_t gui_thread;
if (thrd_create(&gui_thread, guiThread, cairo) != thrd_success) {
return 1;
}
XMapWindow(display, main_window);
XFlush(display);
while (!have_been_killed) {
XEvent event;
XNextEvent(display, &event);
switch (event.type) {
case ConfigureNotify: {
XConfigureEvent e = event.xconfigure;
if (e.window != main_window) {
break;
}
cairo_xlib_surface_set_size(main_surface, e.width, e.height);
break;
}
case ClientMessage: {
XClientMessageEvent e = event.xclient;
if (e.window == main_window && (Atom)e.data.l[0] == WM_DELETE_WINDOW) {
have_been_killed = true;
}
break;
}
default:
}
}
thrd_join(gui_thread, nullptr);
XCloseDisplay(display);
return 0;
}
int guiThread(void *const data) {
cairo_t *const ctx = data;
while (!have_been_killed) {
// Paint a solid colour to simulate an actual GUI
cairo_set_source_rgb(ctx, 70.0/255, 130.0/255, 180.0/255);
cairo_paint(ctx);
cairo_surface_flush(main_surface);
XFlush(display);
thrd_sleep(&(struct timespec){.tv_nsec = 10'000'000}, nullptr);
}
return 0;
}
在创建窗口时需要大量的样板代码,不过我把最关键的代码放在了底部。
对我来说,闪烁只在向内调整大小时才会发生,但有些其他用户表示在任意方向调整大小时都会出现。无论如何,这很让人恼火,所以我该如何让它不再发生呢?
解决方案
这似乎是X11的一个问题。不过,可以很容易地缓解。
由于你自己绘制了整个窗口区域,因此窗口不需要背景色。因此,你可以不用设置一个背景色—从 XCreateWindow 调用中移除 CWBackPixel 和 .background_pixel = 0xFF1E1E1E。
这会把窗口背景设为无背景,因此X11就不会在你的GUI上方绘制实色背景,而是直接不在上面绘制任何东西。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。