【问题标题】:Equivalent of "Invalidate Rect" / "WM_PAINT" in X11等效于 X11 中的“Invalidate Rect”/“WM_PAINT”
【发布时间】:2013-06-06 08:26:12
【问题描述】:

我正在将一些代码从 Windows 移植到 XLib。在 Windows 代码中,我可以通过调用 InvalidateRect 然后处理相应的 WM_PAINT 消息来强制重绘。但是,我无法在 X11/XLib 中找到如何执行此操作。我看到有一条Expose 消息,但不确定是否是同一件事。

如果这很重要,我需要这样做以强制窗口以特定帧速率为基于 OpenGL 的程序呈现。

【问题讨论】:

  • 另外,如果有人能推荐一个很棒的 XLib 参考资料,我将不胜感激。 X.org 上的 XLib 手册似乎对初学者没有太大帮助,至少对我没有。
  • 是的,它是一回事。我强烈建议不要使用原始 Xlib。使用现代工具包,如 Qt、gtk 或 wX。
  • 另外,虽然 Expose 可以工作,但我建议直接调用你的重绘函数。它更简单、更直接。
  • 我只需要一个简单的显示。所有的绘图都是通过opengl完成的,这个应用程序必须在嵌入式系统上运行,所以我需要它真的很轻,因此需要xlib。
  • 你打电话给XSendEvent

标签: c++ linux x11 xlib


【解决方案1】:

为了稍微扩展 BЈовић 给出的有用答案,

使用原始 Xlib,您可以随时在单个线程中进行绘制,因为每个 Xlib 函数都指定了完整的显示、窗口和上下文。 AFAIK,多线程所有的赌注都没有了。

如果您在桌面环境中,您还必须有一个 Expose 事件处理程序,并选择这些事件。即使你正在编写一个全屏程序,拥有一个也没有什么坏处。

大多数工具包没有那么灵活,只能在指定的事件处理程序中绘制(但在许多其他方面使用起来更好),并且有一些等效于 Windows InvalidateRect。在原始 Xlib 中,您可以通过向自己发送 Expose 事件来获得相同的效果。这样做不会导致任何真正的性能问题,并且会使代码更容易被其他程序员理解,并且更容易移植,所以你也可以这样做。

还有 XClearArea 和 XClearWindow 函数会为您生成 Expose 事件,但它们首先会使用背景颜色擦除部分/全部,这可能会导致闪烁。

使用 OpenGL 会变得有点复杂,因为您还必须使用 GLX。我在网上有一个非常简单的 OpenGL/Xlib 程序 http://cs.anu.edu.au/~hugh.fisher/3dteach/ 这可能是一个有用的例子。

【讨论】:

  • 使用XClearArea(disp, win, 0, 0, 1, 1, true) 清除一个像素区域足以导致Expose event 不添加闪烁。如果您没有立即看到Expose 事件,您可能希望立即使用XFlush() 关注XClearArea()
  • anu 记下了你的例子 :(
【解决方案2】:

您需要处理 Expose 事件。 This tutorial 举例说明如何处理 Expose 事件:

#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/Xatom.h>
#include <X11/keysym.h>
/*Linux users will need to add -ldl to the Makefile to compile 
 *this example.
 */
Display *dis;
Window win;
XEvent report;
GC green_gc;
XColor green_col;
Colormap colormap;
/*
Try changing the green[] = below to a different color.
The color can also be from /usr/X11R6/lib/X11/rgb.txt, such as RoyalBlue4.
A # (number sign) is only needed when using hexadecimal colors.
*/
char green[] = "#00FF00";

int main() {
    dis = XOpenDisplay(NULL);
    win = XCreateSimpleWindow(dis, RootWindow(dis, 0), 1, 1, 500, 500, 0, BlackPixel (dis, 0), BlackPixel(dis, 0));
    XMapWindow(dis, win);
    colormap = DefaultColormap(dis, 0);
    green_gc = XCreateGC(dis, win, 0, 0);
    XParseColor(dis, colormap, green, &green_col);
    XAllocColor(dis, colormap, &green_col);
    XSetForeground(dis, green_gc, green_col.pixel);

    XSelectInput(dis, win, ExposureMask | KeyPressMask | ButtonPressMask);

    XDrawRectangle(dis, win, green_gc, 1, 1, 497, 497);
    XDrawRectangle(dis, win, green_gc, 50, 50, 398, 398);
    XFlush(dis);

    while (1)  {
    XNextEvent(dis, &report);
        switch  (report.type) {
        case Expose:   
            fprintf(stdout, "I have been exposed.\n");
                XDrawRectangle(dis, win, green_gc, 1, 1, 497, 497);
                XDrawRectangle(dis, win, green_gc, 50, 50, 398, 398);
                XFlush(dis);
            break;
            case KeyPress:
        /*Close the program if q is pressed.*/
                if (XLookupKeysym(&report.xkey, 0) == XK_q) {
                exit(0);
                }
            break;
        }
    }

return 0;
}

我可能误解了这个问题。如果你想在你的应用程序中创建 Expose 事件,你可以创建并设置expose event,并使用XSendEvent发送。

【讨论】:

  • 好的。所以在windows中我调用InvalidateRect,它稍后会触发windows发送WM_PAINT消息,此时我渲染我的open gl场景。所以在 X11 中,我会用Expose 消息调用XSendEvent,然后有一个事件循环来处理Expose 消息并呈现open gl 场景?
  • @pauld 不确定我是否关注你。 X11 使用事件系统来通知应用程序有关各种事件。你告诉它你想处理哪些事件。如果要在公开事件上渲染场景,则需要在该事件处理程序中添加渲染代码。我不明白你为什么要为你的应用程序生成暴露事件。
  • 好的,我想我明白了。在 Windows 中,我可以在WM_PAINT 消息期间 绘制到窗口。在 X11 中,似乎我可以随时绘制到窗口,而不仅仅是响应Expose 事件。所以在这种情况下,我不需要生成暴露事件,我可以在准备好时进行绘制。
  • @pauld 你说得对。您需要处理 x11 事件,并在需要时更新图像(例如,当窗口未被覆盖或调整大小时)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-09
  • 1970-01-01
  • 2011-02-04
  • 1970-01-01
  • 2020-10-22
  • 1970-01-01
相关资源
最近更新 更多