LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 01-29-2006, 01:21 PM   #1
AngryLlama
Member
 
Registered: Sep 2004
Location: /dev/urandom
Distribution: Gentoo
Posts: 171

Rep: Reputation: 31
XNextEvent select [solved]


Hello, I have a program that uses XNextEvent in my main loop. When an event occurs, I handle it then the program blocks on XNextEvent.

The problem: I want XNextEvent to block, but I want XNextEvent to timeout and unblock after a certain amount of time (say, 0.1sec). I've been trying to figure out how I could accomplish this with the XNextEvent and XPeekEvent family of functions. I'm handling the problem now by creating two threads. One loops on XNextEvent. The other loops on select. I would really like to remove any threads I don't need.

This problem has been solved. Read this post of this thread.

Last edited by AngryLlama; 09-20-2006 at 08:37 PM.
 
Old 01-30-2006, 08:14 AM   #2
jlliagre
Moderator
 
Registered: Feb 2004
Location: Outside Paris
Distribution: Solaris 11.4, Oracle Linux, Mint, Debian/WSL
Posts: 9,789

Rep: Reputation: 492Reputation: 492Reputation: 492Reputation: 492Reputation: 492
use XPending.
 
Old 01-30-2006, 03:46 PM   #3
AngryLlama
Member
 
Registered: Sep 2004
Location: /dev/urandom
Distribution: Gentoo
Posts: 171

Original Poster
Rep: Reputation: 31
Thanks, but I really don't see how I could use XPending to fix this situation. I'm assuming you mean I can check XPending inside of my timer thread. That is, something like:
Code:
while(1) {
  nanosleep(&ts,NULL);
  MyTimerHandler();
  while( XPending(dpy) ) {
    XNextEvent(m_dpy, &xev);
    MyEventHandler(&xev);
  }
}
I suppose this will work, however, my input will only be accepted as fast as my timer's granularity. That is, if I have a 1sec timer, then all my messages will be dispatched in swarms every 1 second. Besides, I don't see how that code differs from the following code (which has the same problem):

Code:
while(1) {
  nanosleep(&ts,NULL);
  MyTimerHandler();
  while( XCheckWindowEvent(dpy, win, ExposureMask|KeyMask..., &xev) ) {
    MyEventHandler(&xev);
  }
}
I would use threads, except X11 behaves horribly (I even tried putting mutexes liberally at possible critical points). My threaded version looked something like this:

Code:
void* XInputThread(void*) {
  XEvent &xev;
  MyEvent &ev;

  while( someCondition ) {
    XNextEvent(dpy, &xev);
    pthread_mutex_lock(&queueMutex);
    MyEventFromXEvent(&ev, &xev)
    queue.push_back(ev);
    pthread_mutex_unlock(&queueMutex);
    sem_post(&queueSem);
  }
}

void TimerSigHandler(int signum) {
  MyEvent &ev;

  pthread_mutex_lock(&queueMutex);
  MyEventFromTime(&ev, timeval);
  queue.push_back(ev);
  pthread_mutex_unlock(&queueMutex);  
  sem_post(&queueSem);
}

int main() {
  ...

  pthread_create( &xinputThread, NULL, XInputThread, NULL );

  memset (&sa, 0, sizeof (sa));
  sa.sa_handler = &TimerSigHandler;
  sigaction (SIGALRM, &sa, NULL);

  timer.it_value.tv_sec = 0;
  timer.it_value.tv_usec = 10000;
  timer.it_interval.tv_sec = 0;
  timer.it_interval.tv_usec = 10000;
  setitimer (ITIMER_REAL, &timer, NULL);

  ...

  while(1) {
    sem_wait(&queueSem);
    pthread_mutex_lock(&queueMutex);
    ev = queue.top();
    queue.pop();
    pthread_mutex_unlock(&queueMutex);

    ProcessTheEvent(&ev);
  }
  ...

}
I tried simplifying these code listings. The third one (the threaded one) causes widget to be half-drawn or corrupt. I'll also get BadIDChoice, X_CreatePixmap, and sync errors from XLib.

The second snippit _works_ but it is sort of hackerish. The threaded model is much cleaner and more responsive, but it just won't work in XLib.

How do people normally solve this problem? Thank you.

Last edited by AngryLlama; 01-30-2006 at 07:43 PM.
 
Old 01-31-2006, 03:00 AM   #4
jlliagre
Moderator
 
Registered: Feb 2004
Location: Outside Paris
Distribution: Solaris 11.4, Oracle Linux, Mint, Debian/WSL
Posts: 9,789

Rep: Reputation: 492Reputation: 492Reputation: 492Reputation: 492Reputation: 492
Quote:
Originally Posted by AngryLlama
Thanks, but I really don't see how I could use XPending to fix this situation. I'm assuming you mean I can check XPending inside of my timer thread. That is, something like:
Code:
while(1) {
  nanosleep(&ts,NULL);
  MyTimerHandler();
  while( XPending(dpy) ) {
    XNextEvent(m_dpy, &xev);
    MyEventHandler(&xev);
  }
}
Correct
Quote:
I suppose this will work, however, my input will only be accepted as fast as my timer's granularity. That is, if I have a 1sec timer, then all my messages will be dispatched in swarms every 1 second. Besides, I don't see how that code differs from the following code (which has the same problem):

Code:
while(1) {
  nanosleep(&ts,NULL);
  MyTimerHandler();
  while( XCheckWindowEvent(dpy, win, ExposureMask|KeyMask..., &xev) ) {
    MyEventHandler(&xev);
  }
}
It mostly doesn't, the former is just simpler, and you didn't mentioned the XCheckWindowEvent call in your initial posting.
Quote:
I would use threads, except X11 behaves horribly (I even tried putting mutexes liberally at possible critical points).
[...]
I tried simplifying these code listings. The third one (the threaded one) causes widget to be half-drawn or corrupt. I'll also get BadIDChoice, X_CreatePixmap, and sync errors from XLib.

The second snippit _works_ but it is sort of hackerish. The threaded model is much cleaner and more responsive, but it just won't work in XLib.

How do people normally solve this problem? Thank you.
X11 is not thread safe, trying to use threads with it is doomed.

You can have multiple threads, but only one of them can use XLib.

Why not lowering your timer granularity to an acceptable value ?
 
Old 02-02-2006, 04:23 PM   #5
AngryLlama
Member
 
Registered: Sep 2004
Location: /dev/urandom
Distribution: Gentoo
Posts: 171

Original Poster
Rep: Reputation: 31
Quote:
Originally Posted by jlliagre
Correct

It mostly doesn't, the former is just simpler, and you didn't mentioned the XCheckWindowEvent call in your initial posting.


X11 is not thread safe, trying to use threads with it is doomed.

You can have multiple threads, but only one of them can use XLib.

Why not lowering your timer granularity to an acceptable value ?
Yeah, I guess that is what I'll have to do. Its just a shame I cannot funnel these two event types into one work queue. Thanks for the help
 
Old 06-19-2006, 09:38 PM   #6
AngryLlama
Member
 
Registered: Sep 2004
Location: /dev/urandom
Distribution: Gentoo
Posts: 171

Original Poster
Rep: Reputation: 31
Sorry to pull this thread from the grave, but I still need a solution. I tried lowering my timer granularity and calling XCheckIfEvent. This method works... but it uses way too much CPU time. I need a way to block on input or a timer. Just like the select() call for the console.

I am trying to accept user input and use a timer to drive some animation. It would be ideal if the time is adjustable.

Thanks
 
Old 06-19-2006, 11:49 PM   #7
paulsm4
LQ Guru
 
Registered: Mar 2004
Distribution: SusE 8.2
Posts: 5,863
Blog Entries: 1

Rep: Reputation: Disabled
Hi -

If many libraries that are higher-level than Xlib support timers. For example, Xt (and consequently any Xt-based GUI, like Motif) has "XtAppAddTimeOut()". Another example is the GTK+ library, which has gtk_timeout_add () (which I use in one of my own animation viewers).

Perhaps you might consider trying a higher-level library, instead of coding directly in Xlib. Or perhaps you can look at one of these implementations and see how they do it (although I doubt you'll find anything terribly useful).

As far as I know, Xlib doesn't provide any way to create "user defined events", so that option's out, too.

Xlib *can*, however, generate an event when you change a property. Perhaps your "timer" thread might be able to call "XChangeProperty()" and generate a usable Xlib event without too much overhead. Just a thought...

Hope that helps (at least a little bit)

Your .. PSM
 
Old 06-20-2006, 12:32 AM   #8
AngryLlama
Member
 
Registered: Sep 2004
Location: /dev/urandom
Distribution: Gentoo
Posts: 171

Original Poster
Rep: Reputation: 31
Quote:
Originally Posted by paulsm4
Hi -

If many libraries that are higher-level than Xlib support timers. For example, Xt (and consequently any Xt-based GUI, like Motif) has "XtAppAddTimeOut()". Another example is the GTK+ library, which has gtk_timeout_add () (which I use in one of my own animation viewers).

Perhaps you might consider trying a higher-level library, instead of coding directly in Xlib. Or perhaps you can look at one of these implementations and see how they do it (although I doubt you'll find anything terribly useful).

As far as I know, Xlib doesn't provide any way to create "user defined events", so that option's out, too.

Xlib *can*, however, generate an event when you change a property. Perhaps your "timer" thread might be able to call "XChangeProperty()" and generate a usable Xlib event without too much overhead. Just a thought...

Hope that helps (at least a little bit)

Your .. PSM
My code is for a custom toolkit that runs under a variety of screens. Xlib is one of the "screens" it supports, but using another widget toolkit is not an option. I will the the ChangeProperty hack and see how well that performs... I'm surprised there is not a better way to do this. It seems like a pretty common thing.
 
Old 09-12-2006, 05:40 PM   #9
AngryLlama
Member
 
Registered: Sep 2004
Location: /dev/urandom
Distribution: Gentoo
Posts: 171

Original Poster
Rep: Reputation: 31
Quote:
Originally Posted by AngryLlama
My code is for a custom toolkit that runs under a variety of screens. Xlib is one of the "screens" it supports, but using another widget toolkit is not an option. I will the the ChangeProperty hack and see how well that performs... I'm surprised there is not a better way to do this. It seems like a pretty common thing.
Using ChangeProperty has even worse results then constantly running a finegrained timer. There has to be some way to do this. How do X apps (and toolkits) allow for animation? I mean, right now I have a caret that blinks while I am able to type. This problem has set my development back for over a month and I still don't have a solution.
 
Old 09-20-2006, 08:33 PM   #10
AngryLlama
Member
 
Registered: Sep 2004
Location: /dev/urandom
Distribution: Gentoo
Posts: 171

Original Poster
Rep: Reputation: 31
I finally came up with a solution to the problem. The answer is simple but not obvious. I never realized that you could obtain a file descriptor to an X11 display. This example I wrote does this and shows how one can make a loop that accepts X Events while allowing a timeout. Creating an interval timer from my example is just as simple.

Code:
#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

Display *dis;
Window win;
int x11_fd;
fd_set in_fds;

struct timeval tv;
XEvent ev;

int main() {
    dis = XOpenDisplay(NULL);
    win = XCreateSimpleWindow(dis, RootWindow(dis, 0), 1, 1, 256, 256, \
        0, BlackPixel (dis, 0), BlackPixel(dis, 0));
    
    // You don't need all of these. Make the mask as you normally would.
    XSelectInput(dis, win, 
        ExposureMask | KeyPressMask | KeyReleaseMask | PointerMotionMask |
        ButtonPressMask | ButtonReleaseMask  | StructureNotifyMask 
        );

    XMapWindow(dis, win);
    XFlush(dis);
    
    // This returns the FD of the X11 display (or something like that)
    x11_fd = ConnectionNumber(dis);

    // Main loop
    while(1) {
        // Create a File Description Set containing x11_fd
        FD_ZERO(&in_fds);
        FD_SET(x11_fd, &in_fds);

        // Set our timer.  One second sounds good.
        tv.tv_usec = 0;
        tv.tv_sec = 1;

        // Wait for X Event or a Timer
        if (select(x11_fd+1, &in_fds, 0, 0, &tv))
            printf("Event Received!\n");
        else
            // Handle timer here
            printf("Timer Fired!\n");

        // Handle XEvents and flush the input 
        while(XPending(dis))
            XNextEvent(dis, &ev);
    }
    return(0);
}

Last edited by AngryLlama; 09-20-2006 at 08:34 PM.
 
1 members found this post helpful.
Old 09-20-2006, 10:49 PM   #11
AngryLlama
Member
 
Registered: Sep 2004
Location: /dev/urandom
Distribution: Gentoo
Posts: 171

Original Poster
Rep: Reputation: 31
And here is the interval timer that will still accept X input.

Code:
#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <sys/time.h>

#ifndef timeradd
# define timeradd(a, b, result)                           \
   do {                                        \
     (result)->tv_sec = (a)->tv_sec + (b)->tv_sec;                 \
     (result)->tv_usec = (a)->tv_usec + (b)->tv_usec;                  \
     if ((result)->tv_usec >= 1000000)                         \
       {                                       \
     ++(result)->tv_sec;                           \
     (result)->tv_usec -= 1000000;                         \
       }                                       \
   } while (0)
#endif
#ifndef timersub
 # define timersub(a, b, result)                           \
   do {                                        \
     (result)->tv_sec = (a)->tv_sec - (b)->tv_sec;                 \
     (result)->tv_usec = (a)->tv_usec - (b)->tv_usec;                  \
     if ((result)->tv_usec < 0) {                          \
       --(result)->tv_sec;                             \
       (result)->tv_usec += 1000000;                       \
     }                                         \
   } while (0)
#endif


Display *dis;
Window win;
int x11_fd;
fd_set in_fds;

int main() {
    struct timeval tv;
    struct timeval stv;
    struct timeval tv_period;

    XEvent ev;

    dis = XOpenDisplay(NULL);
    win = XCreateSimpleWindow(dis, RootWindow(dis, 0), 1, 1, 256, 256, \
        0, BlackPixel (dis, 0), BlackPixel(dis, 0));
    
    // You don't need all of these. Make the mask as you normally would.
    XSelectInput(dis, win, 
        ExposureMask | KeyPressMask | KeyReleaseMask | PointerMotionMask |
        ButtonPressMask | ButtonReleaseMask  | StructureNotifyMask 
        );

    XMapWindow(dis, win);
    XFlush(dis);
    
    // This returns the FD of the X11 connection (or something like that)
    x11_fd = ConnectionNumber(dis);

    // Set Timer Period (this is how you configure the frequency):
    tv_period.tv_sec = 0;
    tv_period.tv_usec = 500000; // 500000us = 500ms = 0.5s 


    tv.tv_sec = tv_period.tv_sec;       // Set tv=1 sec so select() will timeout.
    tv.tv_usec = tv_period.tv_usec;
    gettimeofday(&stv, 0);              // Get the time of day and
    timeradd(&stv, &tv_period, &stv);   // Trust my math for now.. :)

    // Main loop
    while(1) {
        // Create a File Description Set containing x11_fd
        FD_ZERO(&in_fds);
        FD_SET(x11_fd, &in_fds);


        // Wait for X Event or a Timer
        if (select(x11_fd+1, &in_fds, 0, 0, &tv)) {
            printf("Event Received!\n");

            gettimeofday(&tv, 0);
            timersub(&stv, &tv, &tv);  // set tv = remaining time.
        }
        else {
            printf("Timer Fired!\n");
            // Initialize timer variables again.
            tv.tv_sec = tv_period.tv_sec;       // Set tv=1 sec so select() will timeout.
            tv.tv_usec = tv_period.tv_usec;
            gettimeofday(&stv, 0);
            timeradd(&stv, &tv_period, &stv);  // Trust my math for now.. :)
        }

        // Handle XEvents and flush the input 
        while(XPending(dis))
            XNextEvent(dis, &ev);
    }
    return(0);
}
 
Old 09-21-2006, 12:04 AM   #12
jlliagre
Moderator
 
Registered: Feb 2004
Location: Outside Paris
Distribution: Solaris 11.4, Oracle Linux, Mint, Debian/WSL
Posts: 9,789

Rep: Reputation: 492Reputation: 492Reputation: 492Reputation: 492Reputation: 492
Thanks for the feedback.
I was wondering what the ConnectionNumber call could be used for, now I have a good answer.
By the way, your code won't be portable on OpenVMS.
 
Old 09-21-2006, 12:45 AM   #13
AngryLlama
Member
 
Registered: Sep 2004
Location: /dev/urandom
Distribution: Gentoo
Posts: 171

Original Poster
Rep: Reputation: 31
Quote:
Originally Posted by jlliagre
Thanks for the feedback.
I was wondering what the ConnectionNumber call could be used for, now I have a good answer.
By the way, your code won't be portable on OpenVMS.
Your right about the OpenVMS thing. Doesn't it have some special function for Multiplexed input though? I forget what it is called.. any clues?

EDIT: The function is XMultiplexInput(). I suppose I could do some #ifdefs and make it so the code will run on both. However, if I was using OpenVMS then I wouldn't of had this problem in the first place. And for sake of simplicity..

Last edited by AngryLlama; 09-21-2006 at 12:47 AM.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
select jhon Programming 5 11-01-2005 09:46 PM
Select() did not select my socket thvo Programming 1 05-08-2005 12:20 AM
XNextEvent() non-blocking equivalent in xlib? TTux Linux - Software 1 06-24-2004 10:38 AM
SELECT and INNER JOIN Gerardoj Programming 1 06-07-2004 03:09 PM
what os to select kevinasr Linux - Newbie 2 05-18-2003 06:52 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 09:00 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration