Эквивалент "Invalidate Rect" / "WM_PAINT" в X11

Я переношу некоторый код из Windows в XLib. В коде Windows я могу принудительно выполнить перерисовку, вызвав InvalidateRect, а затем обработать соответствующее сообщение WM_PAINT. Однако у меня возникают проблемы с поиском, как это сделать в X11/XLib. Я вижу сообщение Expose, но не уверен, что это то же самое.

Если это имеет значение, мне нужно сделать это, чтобы заставить окно отображать с определенной частотой кадров для программы на основе OpenGL.

Ответ 1

Вам нужно обработать события Expose. В этом руководстве объясняется пример обработки событий 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 в своем приложении, вы можете создать и установить публикацию события и отправить его с помощью XSendEvent.

Ответ 2

Чтобы немного расширить полезные ответы, данные BЈовић,

С помощью raw Xlib вы можете рисовать в любое время в одном потоке, потому что каждая функция Xlib определяет полный экран, окно и контекст. AFAIK, при многопоточности всех ставок.

У вас также должен быть обработчик события Expose и выбрать для этих событий, если вы находитесь в среде рабочего стола. И это не помешает иметь его, даже если вы пишете полноэкранную программу.

Большинство наборов инструментов не так гибки и только рисуются в назначенный обработчик событий (но гораздо приятнее использовать многими другими способами) и имеют некоторый эквивалент Windows InvalidateRect. В raw Xlib вы получаете тот же эффект, отправив себе событие Expose. Это не приведет к каким-либо серьезным проблемам с производительностью и сделает код более понятным для других программистов и упростит перенос, поэтому вы также можете.

Существуют также функции XClearArea и XClearWindow, которые будут генерировать события Expose для вас, но сначала стирают часть/все с цветом фона, что может привести к мерцанию.

С OpenGL это становится немного сложнее, потому что вам также нужно работать с GLX. У меня очень простая программа OpenGL/Xlib в Интернете http://cs.anu.edu.au/~hugh.fisher/3dteach/ который может быть полезен в качестве примера.