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 |
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
Are you new to LinuxQuestions.org? Visit the following links:
Site Howto |
Site FAQ |
Sitemap |
Register Now
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
|
|
01-29-2006, 01:21 PM
|
#1
|
Member
Registered: Sep 2004
Location: /dev/urandom
Distribution: Gentoo
Posts: 171
Rep:
|
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.
|
|
|
01-30-2006, 08:14 AM
|
#2
|
Moderator
Registered: Feb 2004
Location: Outside Paris
Distribution: Solaris 11.4, Oracle Linux, Mint, Debian/WSL
Posts: 9,789
|
use XPending.
|
|
|
01-30-2006, 03:46 PM
|
#3
|
Member
Registered: Sep 2004
Location: /dev/urandom
Distribution: Gentoo
Posts: 171
Original Poster
Rep:
|
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.
|
|
|
01-31-2006, 03:00 AM
|
#4
|
Moderator
Registered: Feb 2004
Location: Outside Paris
Distribution: Solaris 11.4, Oracle Linux, Mint, Debian/WSL
Posts: 9,789
|
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 ?
|
|
|
02-02-2006, 04:23 PM
|
#5
|
Member
Registered: Sep 2004
Location: /dev/urandom
Distribution: Gentoo
Posts: 171
Original Poster
Rep:
|
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
|
|
|
06-19-2006, 09:38 PM
|
#6
|
Member
Registered: Sep 2004
Location: /dev/urandom
Distribution: Gentoo
Posts: 171
Original Poster
Rep:
|
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
|
|
|
06-19-2006, 11:49 PM
|
#7
|
LQ Guru
Registered: Mar 2004
Distribution: SusE 8.2
Posts: 5,863
Rep:
|
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
|
|
|
06-20-2006, 12:32 AM
|
#8
|
Member
Registered: Sep 2004
Location: /dev/urandom
Distribution: Gentoo
Posts: 171
Original Poster
Rep:
|
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.
|
|
|
09-12-2006, 05:40 PM
|
#9
|
Member
Registered: Sep 2004
Location: /dev/urandom
Distribution: Gentoo
Posts: 171
Original Poster
Rep:
|
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.
|
|
|
09-20-2006, 08:33 PM
|
#10
|
Member
Registered: Sep 2004
Location: /dev/urandom
Distribution: Gentoo
Posts: 171
Original Poster
Rep:
|
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.
|
09-20-2006, 10:49 PM
|
#11
|
Member
Registered: Sep 2004
Location: /dev/urandom
Distribution: Gentoo
Posts: 171
Original Poster
Rep:
|
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);
}
|
|
|
09-21-2006, 12:04 AM
|
#12
|
Moderator
Registered: Feb 2004
Location: Outside Paris
Distribution: Solaris 11.4, Oracle Linux, Mint, Debian/WSL
Posts: 9,789
|
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.
|
|
|
09-21-2006, 12:45 AM
|
#13
|
Member
Registered: Sep 2004
Location: /dev/urandom
Distribution: Gentoo
Posts: 171
Original Poster
Rep:
|
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.
|
|
|
All times are GMT -5. The time now is 02:41 PM.
|
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.
|
Latest Threads
LQ News
|
|