Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

monitoring for non-X events

40 views
Skip to first unread message

jimi

unread,
May 10, 2004, 6:56:00 PM5/10/04
to
Hi everyone,

How do I monitor for non-X events? My specific situation is this: I am
writing a telnet-like application. Once control enters the event loop it
blocks on XNextEvent(). How do I then check for incoming data on the
telnet socket? XNextEvent() only returns when there is an event related
to the keyboard, mouse, or window - it doesn't monitor a socket connection.

I'm just getting started with X, so any help is really appreciated. I
tried reducing my app down to just a single window that displays anything
that comes in over the socket. But I don't know how to get XNextEvent()
to check if the socket has data.

jimi
Vs lbh guvax bs argjbex frphevgl nf na vzzhar flfgrz, Jvaqbjf vf UVI.
-- Wbr Cyhgn

Mike Stroyan

unread,
May 10, 2004, 7:29:27 PM5/10/04
to
jimi <ji...@nodomain.com> wrote:

|How do I monitor for non-X events? My specific situation is this: I am
|writing a telnet-like application. Once control enters the event loop it
|blocks on XNextEvent(). How do I then check for incoming data on the
|telnet socket? XNextEvent() only returns when there is an event related
|to the keyboard, mouse, or window - it doesn't monitor a socket connection.

|I'm just getting started with X, so any help is really appreciated. I
|tried reducing my app down to just a single window that displays anything
|that comes in over the socket. But I don't know how to get XNextEvent()
|to check if the socket has data.

Use XCheckMaskEvent() or XCheckIfEvent() or a "while XPending()
XNextEventselect()" loop. When you empty the event queue use select()
or poll() with both your socket and the fildes from XConnectionNumber().
Remember that you probably need to handle multiple events for one wakeup
from select. Xlib can read and buffer multiple events when you make a
call that returns a single event.

--
Mike Stroyan, mike.s...@hp.com

Mity

unread,
May 11, 2004, 8:30:39 AM5/11/04
to
Hi.

I wrote something similar some time ago. Unfortunatly
I don't have the sources here. So the following is some
code skelet I'm able to reproduce now. It shows how to
play with select() and XNextEvent() together.

It should lead you but don't expect to compile
it at first attempts! I didn't try to compile it.
Also you should to check return values and handle
errors properly as your homework :-)

Finally note that it's somewhat unix/linux-friendly.
On other platforms it wouldn't worked probably...

Mity

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <sys/select.h>
#include <sys/types.h>
#include <errno.h>


/* info about FD */
typedef struct fd_info fd_info_t;
struct fd_info {
int fd;
int user; // 0 .. internal for Xlib, 1 .. our own fd
fd_info_t* next;
}

static fd_set fd_mask; /* set of FD to check */

static fd_info_t* fd_head = NULL; /* list of our fd_infos */
static fd_info_t* fd_tail = NULL;

/* add new FD */
fd_info_t*
fd_add(int fd, int user)
{
fd_info_t* info = (fd_info_t*) malloc(sizeof(fd_info_t));
info->fd = fd;
info->next = NULL;

/* add it into the list */
if(fd_tail)
fd_tail->next = info;
else
fd_head = info;
fd_tail = info;

/* set the fd_set */
FD_SET(fd, &fd_mask);

return info;
}

/* remove FD */
void
fd_remove(fd_info_t* info)
{
fd_info_t* tmp = fd_head;
fd_info_t* tmp_prev = NULL;

while(tmp) {
if(tmp == info) {
if(tmp_prev)
tmp_prev->next = info->next;
else
fd_head = info->next;
FD_CLR(info->fd, &fd_mask);
free(info);
return;
}

tmp_prev = tmp;
tmp = tmp->next;
}
}

/* callback function registered with XAddConnectionWatch() */
void
fd_notify(Display* dpy, XPointer client_data,
int fd, Bool opening, XPointer *watch_data)
{
fd_info_t* info;
if(opening) { /* Xlib opens new internal FD */
info = fd_add(fd, 0);
*watch_data = info;
} else { /* Xlib closes some internal FD */
info = *watch_data;
fd_remove(info);
}
}


static Display* dpy;

/* initialization */
void
open_display(void)
{
FD_ZERO(&fd_mask);
dpy = XOpenConnection(NULL);
fd_add(ConnectioNumber(dpy));
XAddConnectionWatch(dpy, fd_notify, NULL);
}

/* cleaning up */
void
close_display(void)
{
XRemoveConnectionWatch(dpy, fd_notify, NULL);
CloseDisplay(dpy);
dpy = NULL;
while(fd_head)
fd_remove(fd_head);
}


int
main(int argc, char** argv)
{
int i, n;
int fd_socket;
fd_info_t* info;
XEvent evt;
int end = 0;

open_display();

// TODO: init fd_socket

fd_add(fd_socket, 1);

/* main loop */
while(!end) {
/* The XFlush() is required! Normally this is done automatically
* in XNextEvent() but we need to do it before the select() below.
*/
XFlush(dpy);

/* If you want to listen on the socket as well you will need
* other fd_set variable and pass it to the select() as third
* parameter (insted of NULL). Ssee 'man select' for more info.
*
* Also it would require a bit more complicated logic where
* we analyze on which fd is some activity.
*
* However I beleive that after inspecting this source you will
* be able to do it yourself...
*/
n = select(FD_SETSIZE, &fd_mask, NULL, NULL, NULL);
if(n < 0) {
if(errno == EINTR) {
// TODO: select() interrupted by some signal -- handle it
continue;
} else {
// TODO: select() failed, handle the error
exit(-1);
}
}

/* Analyze which FD(s) changed status */
i = 0;
info = fd_head;
while(i < n && info) {
if(FD_ISSET(info->fd, &fd_mask)) {
if(info->user) {
// TODO: something happened on our socket. handle it
} else {
/* Let Xlib to convert the received data to XEvents. */
XProcessInternalConnection(dpy, info->fd);
}
i++;
}
info = info->next;
}

/* Finaly process all queued events. */
while(XIsPending(dpy)) {
XNextEvent(dpy, &evt);
// TODO: process the event here
}
}

close_display();

return 0;
}

0 new messages