X11打不开窗口

问题描述 投票:0回答:2

我正在尝试打开一个 X11 窗口,打印出一个像素,然后添加代码以使 Terminate() 返回 true。但它不会形成一个窗口。这是我的代码:

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <iostream>

int x = 0;
int y = 0;

bool Termination() {
    return true;
}

int main() {
    Display *dspl = XOpenDisplay(NULL);
    if (!dspl) return 1;

    int screenNumber = DefaultScreen(dspl);
    unsigned long white = WhitePixel(dspl, screenNumber);
    unsigned long black = BlackPixel(dspl, screenNumber);

    Window win = XCreateSimpleWindow(dspl, DefaultRootWindow(dspl), 50, 50, 1280, 720, 0, black, white);
    XSetStandardProperties(dspl, win, "Lel", "Gaem", None, NULL, 0, NULL);

    GC gc = XCreateGC(dspl, win, 0,0);
    XSetBackground(dspl, gc, black);
    XSetForeground(dspl, gc, white);
    XClearWindow(dspl, win);
    XMapRaised(dspl, win);

    XDrawPoint(dspl, win, gc, x, y);

    while (Termination())
    {
    }

    XFreeGC(dspl, gc);
    XDestroyWindow(dspl, win);
    XCloseDisplay(dspl);
    printf("Job's done!\n");
    return 0;
}

是什么阻止 X11 显示我的窗口?

c++ x11
2个回答
0
投票

在此之前添加此

  XMapWindow(dspl, win);
  XInternAtom(dspl, "WM_DELETE_WINDOW", False); 

0
投票

我知道这是一个老问题,OP可能不再关心,但我很惊讶它没有更多答案,也许这可以帮助其他人。

虽然 Andrew Nic 的解决方案是偶然起作用的,但你的原始代码没有打开窗口的真正原因是因为 Xlib 两者:

  • A) 将请求分批排队(类似于 Nagle 算法),并且
  • B) 是单线程

在最低级别,Xlib 只是一个库,它将您的 Xlib 调用转换为网络数据包并将它们排入其内部 tx 队列。由于它没有单独的线程运行该队列,因此仅通过在 while 循环中自旋锁,Xlib 永远不会再次获得控制权,因此永远没有机会刷新其传出请求队列,并且服务器永远不会听到您的 CreateWindow 请求。

期望要做的就是遵循这样的模式:

    while (Termination())
    {
        XEvent evt;
        XNextEvent(dspl, &evt);
    }

XNextEvent 会让 Xlib 知道您现在已经完成并隐式刷新任何待处理的请求。或者,您可以通过明确地告诉 Xlib 首先传输它的队列,从技术上让它按原样工作:

    XFlush(dspl);
    while (Termination())
    {
    }

...尽管请注意,在任何程序中,像这样旋转而不至少添加一个短的 usleep() 或 poll() (例如,在循环内“usleep(10 * 1000);”)通常都是不明智的。内核最终会介入并抢占您的进程以保持其他任务继续运行,但其中一个核心的 CPU 使用率将达到 100%。不管怎样,当你的程序变得更加复杂时,你可能很快就会想要运行事件循环。 Xlib 假设您的程序将围绕这样的事件循环构建,这就是原始代码无法按预期工作的原因。

一个例外是从 X 服务器返回某种信息的调用(或者再次在网络级别,它们真正做的是发送数据包并阻塞,直到收到服务器的答复)——这些也迫使 Xlib进行隐式刷新/同步,因为服务器显然需要“赶上”最新的请求才能发送程序正在等待的答复。 InternAtom 就是一个这样的请求,这就是为什么 Andrew Nic 的解决方案顺便解决了这个问题(请注意,查找到的 WM_DELETE_WINDOW 原子从未实际使用过,因此它不执行任何其他操作,并且可能只是一个 XFlush() ,因为这一面 -效果是唯一的效果)。

  • 请注意,诸如 XCreateWindow 之类的调用可能看起来很重要,因为它们返回一个“Window”(实际上只是一个 typedef'd uint32_t“资源 ID”,在原始协议级别称为 xid)——但这些类型的请求实际上不需要需要回复,因此不会强制刷新,因为资源ID实际上是在X11中从服务器在连接时给你的程序的范围中分配的客户端; Xlib 库会为您处理查找免费 xid 的详细信息,但 Xlib 实际上在发送请求之前就知道它将返回给您什么窗口 ID)。

还要注意,虽然在许多现代 DE 中,在循环之前绘制像素确实有效(由于合成器),但为了可靠,您实际上应该等到收到 Expose 事件后再绘制到窗口。至少,如果窗口被覆盖和未覆盖(或图标化/恢复),则通过不在 Expose 上进行重新绘制,您的像素可能会消失。

来源:我通过开发一个通过原始 TCP 套接字与 X 通信的库而熟悉 X11 协议,并且相当熟悉 Xlib 源代码。

© www.soinside.com 2019 - 2024. All rights reserved.