camelccc
camelccc

Reputation: 2992

How to allow a worker thread to update an X11 Window?

I have an application that that I was trying to modify so that a worker thread can tell a window to update itself with new data.

Variables are defined as follows:

Display *d;
Window w;
XEvent exppp;

The window is started with the following code:

XEvent e;

d = XOpenDisplay(NULL);
if (d == NULL) 
  return 0;

s = DefaultScreen(d);
w = XCreateSimpleWindow(d, RootWindow(d, s), 10, 10, 200, 800, 1,
                        BlackPixel(d, s), WhitePixel(d, s));
XSelectInput(d, w, ExposureMask | KeyPressMask);
XMapWindow(d, w);

while (1) {
  XNextEvent(d, &e);
  if (e.type == Expose || e.type == KeyPress) {
    // redraw routine goes here
  }
}

What I was attempting to use to get the window to redraw is a function that can be called by another thread:

void graphical_out::redraw()
{
  exppp.type = Expose;
  XSendEvent(d, w, false, Expose, &exppp);
}

And the window only updates itself when it is re-sized or receives a key-press. This seems a bit like a newbie question but Google has failed me on this one. Any suggestions to what I am doing wrong?

Upvotes: 3

Views: 5673

Answers (1)

n. m. could be an AI
n. m. could be an AI

Reputation: 119877

  1. Your arguments to XSendEvent are wrong. You need to pass the mask (ExposureMask), not the event type.
  2. exppp.xexpose.window = w; is mandatory (the window argument of XSendEvent is not the window of the XEvent structure).
  3. Clean the event before sending it: memset(&exppp, 0, sizeof(exppp));, just in case.
  4. Xlib is not thread-safe and calling its functions from more than one thread may be dangerous.

UPDATE In a multithreaded program one needs to call XFlush here and there (though multithreading is never guaranteed to work with Xlib).

This code works for me:

#include <X11/Xlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <memory.h>

Display *d;
Window w;
int s;

void* tp (void* q)
{
    XEvent exppp;

    while (1)
    {
        sleep (3);
        printf ("Sending event of type Expose\n");
        memset(&exppp, 0, sizeof(exppp));
        exppp.type = Expose;
        exppp.xexpose.window = w;
        XSendEvent(d,w,False,ExposureMask,&exppp);
        XFlush(d);
    }
    return NULL;
}


int main ()
{
    XEvent e;
    pthread_t thread;

    d = XOpenDisplay(NULL);
    if (d == NULL)
        return 0;

    s = DefaultScreen(d);
    w = XCreateSimpleWindow(d, RootWindow(d, s), 10, 10, 200, 800, 1,
                            BlackPixel(d, s), WhitePixel(d, s));
    XSelectInput(d, w, ExposureMask | KeyPressMask);
    XMapWindow(d, w);

    pthread_create(&thread, NULL, tp, NULL);

    while (1) {
        XNextEvent(d, &e);
        if (e.type == Expose) {
            printf ("Got Expose event%s\n", e.xexpose.send_event ? " (SendEvent)" : "");
        }
        else if (e.type == KeyPress) {
            printf ("Got KeyPress event%s\n", e.xkey.send_event ? " (SendEvent)" : "");
        }
    }
}

It might work for you, or it might bomb. Xlib is not thread safe, use at your own risk.

Upvotes: 6

Related Questions