Xlib: Closing window always causes fatal IO error? - c++

I'm not sure why this happens, but any window I create using Xlib in C++ gives outputs an error to the terminal when I try to close is using the X button. I can close it programmatically with no errors, it's just the X button that does it.
The error is the following:
XIO: fatal IO error 11 (Resource temporarily unavailable) on X server ":0"
after 483 requests (483 known processed) with 0 events remaining.
The number of requests is different every time, but there's always 0 events remaining. Why does this happen? The cause doesn't seem to be my code, since it does this no matter what and sends no close events to the queue. I've tried intercepting the Atom WM_WINDOW_DELETE, and it doesn't run over the expected code when I close the window.
Edit: Added event loop code.
while(XPending(display)) {
XNextEvent(display, &event);
pthread_mutex_unlock(&mutex);
if(event.type == Expose) {
XWindowAttributes getWindowAttributes;
pthread_mutex_lock(&mutex);
XGetWindowAttributes(display, window, &getWindowAttributes);
if(state.currentState == STATE_NORMAL) {
state.normX = getWindowAttributes.x;
state.normY = getWindowAttributes.y;
state.normWidth = getWindowAttributes.width;
state.normHeight = getWindowAttributes.height;
}
pthread_mutex_unlock(&mutex);
glViewport(0, 0, getWindowAttributes.width, getWindowAttributes.height);
} else if(event.type == KeyPress) {
return false;
} else if(event.type == ClientMessage) {
std::cout<<"X Button pressed"<<std::endl; //Never run when X-ing window
if(event.xclient.message_type == XInternAtom(display, "WM_DELETE_WINDOW", True)) {
return false;
}
} else if(event.type == ButtonPress) {
if(state.currentState != STATE_FULLSCREEN) {
fullscreen();
} else {
normalize();
}
} else if(!handleEvent(event)){
return false;
}
pthread_mutex_lock(&mutex);
}

In addition to WM_WINDOW_DELETE you need to listen for and handle the ClientMessage event.
Modifying the example from Rosetta Code to illustrate:
#include <X11/Xlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
Display *d;
Window w;
XEvent e;
const char *msg = "Hello, World!";
int s;
d = XOpenDisplay(NULL);
if (d == NULL) {
fprintf(stderr, "Cannot open display\n");
exit(1);
}
s = DefaultScreen(d);
w = XCreateSimpleWindow(d, RootWindow(d, s), 10, 10, 100, 100, 1, BlackPixel(d, s), WhitePixel(d, s));
XSelectInput(d, w, ExposureMask | KeyPressMask);
XMapWindow(d, w);
// I support the WM_DELETE_WINDOW protocol
Atom WM_DELETE_WINDOW = XInternAtom(d, "WM_DELETE_WINDOW", False);
XSetWMProtocols(d, w, &WM_DELETE_WINDOW, 1);
while (1) {
XNextEvent(d, &e);
if (e.type == Expose) {
XFillRectangle(d, w, DefaultGC(d, s), 20, 20, 10, 10);
XDrawString(d, w, DefaultGC(d, s), 10, 50, msg, strlen(msg));
}
else if (e.type == KeyPress)
break;
else if (e.type == ClientMessage)
// TODO Should check here for other client message types -
// however as the only protocol registered above is WM_DELETE_WINDOW
// it is safe for this small example.
break;
}
XCloseDisplay(d);
return 0;
}

Related

SDL_WINDOWEVENT_SIZE_CHANGED and SDL_WINDOWEVENT_RESIZED not working?

I'm trying to detect, when the size of a SDL2 window changed. But neither SDL_WINDOWEVENT_RESIZED nor SDL_WINDOWEVENT_SIZE_CHANGED are working, at least on MacOS.
This is my code:
SDL_Init(SDL_INIT_VIDEO);
SDL_Window *win = SDL_CreateWindow("", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 100, 100, SDL_WINDOW_RESIZABLE);
SDL_Renderer *ren = SDL_CreateRenderer(win, 0, 0);
bool running = true;
SDL_Event event;
while (running) {
while(SDL_PollEvent(&event) != 0) {
if(event.type == SDL_QUIT) {
running = false;
}
if(event.type == SDL_WINDOWEVENT_SIZE_CHANGED) {
return 3;
}
if(event.type == SDL_WINDOWEVENT_RESIZED) {
return 4;
}
}
SDL_RenderClear(ren);
}
SDL_DestroyRenderer(ren);
SDL_DestroyWindow(win);
SDL_Quit();
return 0;
When running the program and resizing the window nothing happens. Am I doing something wrong or is it a bug?
Edit: I looked up the documentation on window events(https://wiki.libsdl.org/SDL_WindowEvent).
It says to write something like this:
event.window.type == SDL_WINDOWEVENT_SIZE_CHANGED
But this also isn't working.
SDL_WINDOWEVENT_* are not event types but SDL_WindowEventID. That is, if your event.type is SDL_WINDOWEVENT, you can access window union field for extra data, including event, e.g.
while(SDL_PollEvent(&event)) {
if(event.type == SDL_WINDOWEVENT) {
if(event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
// ...
}
}
}

Need this to play music

Game dev class. Trying to understand what i did wrong here. Did I add the wrong thing, or do i have it at the wrong place.
my goal was to add music.
#include "allegro5/allegro.h"
#include <allegro5/allegro_image.h>
#include <allegro5/allegro_font.h>
#include <allegro5/allegro_ttf.h>
#include <allegro5/allegro_native_dialog.h>
#include <stdio.h>
#include <string>
#include <allegro5\allegro_audio.h>
#include <allegro5\allegro_acodec.h>
#define FPS 60
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600
#define BLACK al_map_rgb(0, 0, 0)
#define WHITE al_map_rgb(255, 255, 255)
//Prototypes
bool initializeAllegro();
//Essential Allegro pointers
ALLEGRO_DISPLAY *display = NULL;
ALLEGRO_EVENT_QUEUE *eventQueue = NULL;
ALLEGRO_TIMER *timer = NULL;
ALLEGRO_FONT *arial14;
int main()
{
ALLEGRO_BITMAP *backgroundImage; //Bitmap for the background image(star field)
int backgroundImageWidth = 0, backgroundImageHeight = 0;
bool redrawRequired = true;
//Using std:string for name, so length is not a factor
std::string userName = "";
std::string prompt1 = "Enter your Player's name below";
std::string prompt2 = "(Letters & digits only. Backspace to erase.)";
std::string prompt3 = "Press Enter to accept...";
std::string prompt4 = "Press Escape to exit...";
char keyToAdd = ' ';
bool enteringUserName = true;
bool quit = false;
//Initialize allegro, etc
if (!initializeAllegro()) return -1;
//load the arial font
arial14 = al_load_font("arial-mt-black.ttf", 14, 0);
if (!arial14)
{
return -3;
}
//test running music
al_init_acodec_addon();
ALLEGRO_SAMPLE *song = al_load_sample("hideandseek.wav");
ALLEGRO_SAMPLE_INSTANCE *songInstance = al_create_sample_instance(song);
al_set_sample_instance_playmode(songInstance, ALLEGRO_PLAYMODE_LOOP);
al_attach_sample_instance_to_mixer(songInstance, al_get_default_mixer());
//Load the background picture
if (!(backgroundImage = al_load_bitmap("starbackground.bmp")))
{
return -5;
}
//Get dimensions of the background image
backgroundImageWidth = al_get_bitmap_width(backgroundImage);
backgroundImageHeight = al_get_bitmap_height(backgroundImage);
//Set the back buffer as the drawing bitmap for the display
al_set_target_bitmap(al_get_backbuffer(display));
//Initialize the event queue
eventQueue = al_create_event_queue();
if (!eventQueue)
{
al_destroy_display(display);
al_destroy_timer(timer);
return -1;
}
//Register events as arriving from these sources: display, timer, keyboard
al_register_event_source(eventQueue, al_get_display_event_source(display));
al_register_event_source(eventQueue, al_get_timer_event_source(timer));
al_register_event_source(eventQueue, al_get_keyboard_event_source());
al_flip_display();
//play song
al_play_sample_instance(songInstance);
//Start up the timer. Don't do this until just before the game is to start!
al_start_timer(timer);
//This would be a loop solely for entering the user's name, not starting the game
//Allegro keycodes are laid out as follows. (Full set of key codes is included in keycodes.h)
//Key codes for capital letters are 1 - 26 for A - Z
//Digit values are 27 - 36 for the top digits (0 - 9), and 37 - 46 for the keypad
while (!quit)
{
ALLEGRO_EVENT evt;
//Wait for one of the allegro-defined events
al_wait_for_event(eventQueue, &evt);
//An event was generated. Check for all possible event types
switch (evt.type)
{
case ALLEGRO_EVENT_KEY_CHAR:
if (evt.keyboard.keycode >= 1 && evt.keyboard.keycode <= 26) //It's a capital letter
{
//Convert to ASCII capital
keyToAdd = *al_keycode_to_name(evt.keyboard.keycode);
userName += keyToAdd;
}
else if (evt.keyboard.keycode >= 27 && evt.keyboard.keycode <= 36)
{
//Convert to digit
keyToAdd = evt.keyboard.keycode + 21;
userName += keyToAdd;
}
//Handle digits on keypad
else if (evt.keyboard.keycode >= 37 && evt.keyboard.keycode <= 46)
{
//Convert to digit
keyToAdd = evt.keyboard.keycode + 11;
userName += keyToAdd;
}
else //Handle a few other keys
{
switch(evt.keyboard.keycode)
{
case ALLEGRO_KEY_BACKSPACE:
if (userName.length() > 0)
userName = userName.substr(0, userName.length() - 1);
break;
//Enter key stops username entry
case ALLEGRO_KEY_ENTER:
case ALLEGRO_KEY_PAD_ENTER:
enteringUserName = false;
break;
case ALLEGRO_KEY_ESCAPE:
quit = true;
break;
}
}
break;
case ALLEGRO_EVENT_DISPLAY_CLOSE:
quit = true;
break;
case ALLEGRO_EVENT_TIMER:
redrawRequired = true;
break;
}//END switch evt.type
//Rerender the entire scene
if (redrawRequired && al_is_event_queue_empty(eventQueue))
{
redrawRequired = false;
al_clear_to_color(BLACK); //Just in case
//Draw background
al_draw_scaled_bitmap(backgroundImage, 0, 0, backgroundImageWidth, backgroundImageHeight,
0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0);
//Prompt for name to be entered
al_draw_textf (arial14, WHITE, 0, 30, 0, "%s", prompt1.c_str());
al_draw_textf (arial14, WHITE, 0, 50, 0, "%s", prompt2.c_str());
if (userName.length() > 0)
{
if (enteringUserName)
{
al_draw_textf (arial14, WHITE, 0, 70, 0, "%s", userName.c_str());
al_draw_textf (arial14, WHITE, 0, 90, 0, "%s", prompt3.c_str());
}
else
{
al_draw_textf (arial14, WHITE, 0, 70, 0, "You entered your name as-->%s", userName.c_str());
}
}
al_draw_textf(arial14, WHITE, 0, 400, 0, "%s", prompt4.c_str());
al_flip_display();
}//END rendering the screen
}//END input Loop
//Release all dynamically allocated memory
al_destroy_bitmap(backgroundImage);
al_destroy_font(arial14);
al_destroy_timer(timer);
al_destroy_display(display);
al_destroy_event_queue(eventQueue);
//destroy songs
al_destroy_sample(song);
al_destroy_sample_instance(songInstance);
return 0;
}//END main
//Take care of Allegro initialization tasks
//Return false if any fail.
bool initializeAllegro()
{
bool success = true;
//Init basic environment
if (!al_init())
{
al_show_native_message_box(NULL, "ERROR", "Allegro failed to initialize!", NULL, NULL, NULL);
success = false;
}
//Initialize keyboard input
if (!al_install_keyboard())
{
al_show_native_message_box(NULL, "ERROR", "Keyboard failed to initialize!", NULL, NULL, NULL);
success = false;
}
//Initialize timer
timer = al_create_timer(1.0 / FPS);
if (!timer)
{
al_show_native_message_box(NULL, "ERROR", "Timer failed to initialize!", NULL, NULL, NULL);
success = false;
}
//Initialize display
display = al_create_display(SCREEN_WIDTH, SCREEN_HEIGHT);
if (!display)
{
al_show_native_message_box(NULL, "ERROR", "Display failed to initialize!", NULL, NULL, NULL);
success = false;
}
//Initialize the image mechanism
if (!al_init_image_addon())
{
al_show_native_message_box(NULL, "ERROR", "Image addon failed to initialize!", NULL, NULL, NULL);
success = false;
}
al_init_font_addon();
al_init_ttf_addon();
return success;
}//END initializeAllegro
Any wav file should work.
i get the error message -
First-chance exception at 0x0F196486
(allegro-5.0.10-monolith-md-debug.dll) in User Input Project.exe:
0xC0000005: Access violation reading location 0x00000000. Unhandled
exception at 0x0F196486 (allegro-5.0.10-monolith-md-debug.dll) in User
Input Project.exe: 0xC0000005: Access violation reading location
0x00000000.
The program '[9596] User Input Project.exe' has exited with code 0
(0x0).
I mentioned to step through things with a debugger in my comment, but the code smell here is this:
ALLEGRO_SAMPLE *song = al_load_sample("hideandseek.wav");
ALLEGRO_SAMPLE_INSTANCE *songInstance = al_create_sample_instance(song);
You should Definitely be checking for (song == NULL) before you call al_create_sample_instance()
If your path to the .WAV file is wrong or if the loading fails for any other reason, then al_load_sample() will return NULL, and you shouldn't be trying to do anything with song

XOpenDisplay failing

I'm writing a simple window class which is failing to return a display. Here's the short version:
#include <X11/Xlib.h>
#include <stdio.h>
#include <stdlib.h>
class WindowImpl
{
public:
WindowImpl()
{
open = true;
}
WindowImpl(float width, float height)
{
if(!create(width, height))
{
fprintf(stderr, "Could not open display\n");
exit(1);
}
open = true;
}
~WindowImpl()
{
XCloseDisplay(display);
};
bool create(float width, float height)
{
display = XOpenDisplay(NULL);
if(display == NULL)
return false;
int displayID = DefaultScreen(display);
window = XCreateSimpleWindow(display, RootWindow(display, displayID), 10, 10, width, height, 1, BlackPixel(display, displayID), WhitePixel(display, displayID));
XMapWindow(display, window);
return true;
}
bool isOpen()
{
return open;
}
void close()
{
open == false;
}
private:
Display* display;
Window window;
bool open;
};
int main()
{
WindowImpl myWindow(1920, 1080);
char* cmd;
while(myWindow.isOpen())
{
if(gets(cmd) == "close")
myWindow.close();
}
return 0;
}
WindowImpl::create fails, XOpenDisplay is returning NULL but I'm not sure why. Hopefully someone could shed some light on the problem here.
Edit: Changing WindowImpl::create to return true and false instead of 0 and 1 causes it to go through but the window still doesn't open;
For clarification:
#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
Display* display;
Window window;
XEvent event;
char* message = "Hello";
int screenSize;
display = XOpenDisplay(NULL);
if(display == NULL)
{
fprintf(stderr, "Cannot open display\n");
exit(1);
}
screenSize = DefaultScreen(display);
window = XCreateSimpleWindow(display, RootWindow(display, screenSize), 10, 10, 1920, 1080, 1, BlackPixel(display, screenSize), WhitePixel(display, screenSize));
XSelectInput(display, window, ExposureMask | KeyPressMask);
XMapWindow(display, window);
KeySym keysym = XK_Escape;
KeyCode keycode = XKeysymToKeycode(display, keysym);
while(true)
{
XNextEvent(display, &event);
if(event.type == KeyPress && event.xkey.keycode == keycode)
break;
}
XCloseDisplay(display);
return 0;
}
Compiles and runs just fine.
When you create a windows, you need to let the X server to handle output buffer. Normally this is done when you enter into the window event loop, i.e. calling any function that has EVENT in its name.
Once you are not dealing with events in your code, another way to flush the output buffer is calling XFlush, as said in its manual:
The XFlush function flushes the output buffer. Most client applications need not use this function because the output buffer is automatically flushed as needed by calls to XPending, XNextEvent, and XWindowEvent. Events generated by the server may be enqueued into the library's event queue.
The XSync function flushes the output buffer and then waits until all requests have been received and processed by the X server.
So, to solve your issue, I suggest to put this line of code:
window = XCreateSimpleWindow(display, RootWindow(display, displayID), 10, 10, width, height, 1, BlackPixel(display, displayID), WhitePixel(display, displayID));
XMapWindow(display, window);
XFlush(display); // <------------
return true;

I want to make splash screen and now I have two problems?

1: I want to have a splash screen but I only have a window?so,how to do with sth like parm
2: I've used a while(!done) to draw the window so how to break out with a function or sth else
here is my code and much thx to you
g++ -o m_splash m_splash.cpp -lX11 -lImlib2
#include <stdio.h>
#include <X11/Xlib.h>
#include <Imlib2.h>
#include <unistd.h>
int main()
{
Imlib_Image m_img;
Display *m_dpy;
Pixmap m_pix;
Window m_root;
Screen *scn;
int m_width, m_height;
const char *filename = "/home/ang/so_zt/w.png";
m_img = imlib_load_image(filename);
if(!m_img)
{
printf("%s\n","init m_img faild");
}
imlib_context_set_image(m_img);
m_width = imlib_image_get_width();
m_height = imlib_image_get_height();
m_dpy = XOpenDisplay(NULL);
if(!m_dpy)
{
printf("%s\n","open display failed");
}
scn = DefaultScreenOfDisplay(m_dpy);
int s = DefaultScreen(m_dpy);
m_root = XCreateSimpleWindow(m_dpy, RootWindow(m_dpy,s),10,10,m_width,m_height,0,
BlackPixel(m_dpy, s), WhitePixel(m_dpy, s));
m_pix = XCreatePixmap(m_dpy, m_root, m_width, m_height, DefaultDepthOfScreen(scn));
imlib_context_set_display(m_dpy);
imlib_context_set_visual(DefaultVisualOfScreen(scn));
imlib_context_set_colormap(DefaultColormapOfScreen(scn));
imlib_context_set_drawable(m_pix);
imlib_render_image_on_drawable(0,0);
XSetWindowBackgroundPixmap(m_dpy, m_root, m_pix);
XClearWindow(m_dpy, m_root);
Atom wmDeleteMessage = XInternAtom(m_dpy, "WM_DELETE_WINDOW", False);
XSetWMProtocols(m_dpy, m_root, &wmDeleteMessage, 1);
XSelectInput(m_dpy, m_root, ExposureMask | KeyPressMask | StructureNotifyMask);
XMapWindow(m_dpy, m_root);
bool done = false;
while (!done)
{
XEvent m_ev;
XNextEvent(m_dpy, &m_ev);
/* draw or redraw the window */
if (m_ev.type == Expose)
{
XFillRectangle(m_dpy, m_root, DefaultGC(m_dpy, DefaultScreen(m_dpy)), 20, 20, 10, 10);
}
/* exit on key press */
//usleep(1000000);
//done = true;
switch(m_ev.type)
{
case KeyPress:
XDestroyWindow(m_dpy, m_root);
break;
case DestroyNotify:
done = true;
break;
case ClientMessage:
if (m_ev.xclient.data.l[0] == wmDeleteMessage)
{
done = true;
}
break;
}
}
//XFreePixmap(m_dpy, m_pix);
//imlib_free_image();
//XCloseDisplay(m_dpy);
}
To make it a splash screen, use extended window manager hints.
#include <X11/Xatom.h>
Atom type = XInternAtom(m_dpy, "_NET_WM_WINDOW_TYPE", False);
Atom value = XInternAtom(m_dpy, "_NET_WM_WINDOW_TYPE_SPLASH", False);
XChangeProperty(m_dpy, m_root, type, XA_ATOM, 32, PropModeReplace, reinterpret_cast<unsigned char*>(&value), 1);
The window then appears without decorations and stays until clicked.
When clicked you get an UnmapNotify event, so this what you should use to set done.
To avoid having to get events, add
XFlush(m_dpy);
after mapping the window to display it and
XUnmapWindow(m_dpy, m_root);
when you want to get rid of it.
In this example the program just sleeps for 5 seconds before continuing:
#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <Imlib2.h>
#include <unistd.h>
int main()
{
Imlib_Image m_img;
Display *m_dpy;
Pixmap m_pix;
Window m_root;
Screen *scn;
int m_width, m_height;
const char *filename = "w.png";
m_img = imlib_load_image(filename);
if(!m_img)
{
printf("%s\n","init m_img faild");
}
imlib_context_set_image(m_img);
m_width = imlib_image_get_width();
m_height = imlib_image_get_height();
m_dpy = XOpenDisplay(NULL);
if(!m_dpy)
{
printf("%s\n","open display failed");
}
scn = DefaultScreenOfDisplay(m_dpy);
int s = DefaultScreen(m_dpy);
m_root = XCreateSimpleWindow(m_dpy, RootWindow(m_dpy,s),10,10,m_width,m_height,0,
BlackPixel(m_dpy, s), WhitePixel(m_dpy, s));
m_pix = XCreatePixmap(m_dpy, m_root, m_width, m_height, DefaultDepthOfScreen(scn));
Atom type = XInternAtom(m_dpy, "_NET_WM_WINDOW_TYPE", False);
Atom value = XInternAtom(m_dpy, "_NET_WM_WINDOW_TYPE_SPLASH", False);
XChangeProperty(m_dpy, m_root, type, XA_ATOM, 32, PropModeReplace, reinterpret_cast<unsigned char*>(&value), 1);
imlib_context_set_display(m_dpy);
imlib_context_set_visual(DefaultVisualOfScreen(scn));
imlib_context_set_colormap(DefaultColormapOfScreen(scn));
imlib_context_set_drawable(m_pix);
imlib_render_image_on_drawable(0,0);
XSetWindowBackgroundPixmap(m_dpy, m_root, m_pix);
XClearWindow(m_dpy, m_root);
Atom wmDeleteMessage = XInternAtom(m_dpy, "WM_DELETE_WINDOW", False);
XSetWMProtocols(m_dpy, m_root, &wmDeleteMessage, 1);
XMapWindow(m_dpy, m_root);
XFlush(m_dpy);
sleep(5);
XUnmapWindow(m_dpy, m_root);
}
and this program can have a splash with hello world alse I do not know how to jump out of the while(!done) so much thx to U
g++ -o test_chr test_chr.cpp -lX11
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(void)
{
Display *d;
Window w;
XEvent e;
const char *msg = "Hello, World!";
int s;
bool done = false;
/* open connection with the server */
d = XOpenDisplay(NULL);
if (d == NULL)
{
fprintf(stderr, "Cannot open display\n");
exit(1);
}
s = DefaultScreen(d);
/* create window */
w = XCreateSimpleWindow(d, RootWindow(d, s), 10, 10, 480, 320, 0,BlackPixel(d, s), WhitePixel(d, s));
Atom type = XInternAtom(d,"_NET_WM_WINDOW_TYPE", False);
Atom value = XInternAtom(d,"_NET_WM_WINDOW_TYPE_SPLASH", False);
XChangeProperty(d, w, type, XA_ATOM, 32, PropModeReplace, reinterpret_cast<unsigned char*>(&value), 1);
/* register interest in the delete window message */
Atom wmDeleteMessage = XInternAtom(d, "WM_DELETE_WINDOW", False);
XSetWMProtocols(d, w, &wmDeleteMessage, 1);
/* select kind of events we are interested in */
XSelectInput(d, w, ExposureMask | KeyPressMask | StructureNotifyMask);
/* map (show) the window */
XMapWindow(d, w);
/* event loop */
while (!done)
{
XNextEvent(d, &e);
/* draw or redraw the window */
if (e.type == Expose)
{
XDrawString(d, w, DefaultGC(d, s), 50, 50, msg, strlen(msg));
}
/* exit on key press */
switch(e.type)
{
case KeyPress:
XDestroyWindow(d, w);
break;
case DestroyNotify:
done = true;
break;
case ClientMessage:
if (e.xclient.data.l[0] == wmDeleteMessage)
{
done = true;
}
break;
}
}
/* close connection to server */
XCloseDisplay(d);
return 0;
}

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?
Your arguments to XSendEvent are wrong. You need to pass the mask (ExposureMask), not the event type.
exppp.xexpose.window = w; is mandatory (the window argument of XSendEvent is not the window of the XEvent structure).
Clean the event before sending it: memset(&exppp, 0, sizeof(exppp));, just in case.
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.