Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Equivalent of "Invalidate Rect" / "WM_PAINT" in X11

Tags:

c++

linux

x11

xlib

I'm Porting some code from Windows to XLib. In the windows code, I can force a redraw by calling InvalidateRect and then handling the corresponding WM_PAINT message. However, I am having trouble finding out how to do this in X11/XLib. I see there is an Expose message but not sure if that is the same thing.

If it matters, I need to do this to force the window to render at a certain frame rate for an OpenGL based program.

like image 591
default Avatar asked Jun 10 '13 15:06

default


2 Answers

To expand slightly on the useful answers given by BЈовић,

With raw Xlib you can draw at any time in a single thread, because every Xlib function specifies the full display, window, and context. AFAIK, with multithreading all bets are off.

You also must have an Expose event handler, and select for those events, if you're in a desktop environment. And it won't hurt to have one even if you're writing a full screen program.

Most toolkits are not as flexible and only draw in a designated event handler (but much nicer to use in many other ways) and have some equivalent to the Windows InvalidateRect. In raw Xlib you get the same effect by sending yourself an Expose event. Doing so won't lead to any real performance problems and will make the code more understandable by other programmers, and easier to port, so you might as well.

There are also XClearArea and XClearWindow functions which will generate Expose events for you, but they first erase part/all with the background color, which might lead to flickering.

With OpenGL it gets a bit more complicated because you have to work with GLX as well. I have a very simple OpenGL/Xlib program online at http://cs.anu.edu.au/~hugh.fisher/3dteach/ which might be useful as an example.

like image 150
Hugh Fisher Avatar answered Sep 28 '22 11:09

Hugh Fisher


You need to handle Expose events. This tutorial explains with an example how to handle Expose events :

#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;
}

I may have misunderstood the question. If you want to create Expose events in your application, you can create and set expose event, and send it using XSendEvent.

like image 39
BЈовић Avatar answered Sep 28 '22 11:09

BЈовић