/* * notify.c -- Demonstrates how to bypass xv_main_loop() by creating your * own event loop. */ #include <X11/Xlib.h> #include <sys/types.h> #include <sys/time.h> #include <xview/xview.h> #include <xview/canvas.h> #include <xview/textsw.h> #include <xview/xv_xrect.h> void event_proc(), repaint_proc(); char kbd_msg[128], ptr_msg[128], but_msg[128]; int RUN = TRUE; XFontStruct *font; /* Time out for select. */ #ifndef __linux__ struct timeval timeout = { 0, 250000 }; #else // struct timeval timeout; /* Linux changes timeval in select(), reinit every time */ #endif // main(argc, argv) int argc; char *argv[]; { Display *dpy; Frame frame; Textsw textsw; Canvas canvas; fd_set readfds; int fd; Notify_func my_destroy_func(); /* Initialize XView */ xv_init(XV_INIT_ARGC_PTR_ARGV, &argc, argv, NULL); /* Create windows -- base frame, canvas and a textsw. */ frame = (Frame)xv_create(NULL, FRAME, XV_X, 10, XV_Y, 10, XV_LABEL, "Notifier", NULL); /* Interpose on the frame's destroy proc so I know when the user has * selected quit from the menu. I don't want to get into a position * where all my windows are gone, but my main loop is still spinning * away. */ notify_interpose_destroy_func(frame, (Notify_func) my_destroy_func); canvas = xv_create(frame, CANVAS, XV_WIDTH, 520, XV_HEIGHT, 130, CANVAS_X_PAINT_WINDOW, TRUE, CANVAS_REPAINT_PROC, repaint_proc, /* Set attrs on the paint window */ CANVAS_PAINTWINDOW_ATTRS, WIN_EVENT_PROC, event_proc, WIN_CONSUME_EVENTS, KBD_DONE, KBD_USE, LOC_DRAG, LOC_MOVE, LOC_WINENTER, LOC_WINEXIT, WIN_ASCII_EVENTS, WIN_MOUSE_BUTTONS, NULL, NULL, NULL); textsw = xv_create(frame, TEXTSW, XV_X, 0, WIN_BELOW, canvas, XV_WIDTH, 520, XV_HEIGHT, 500, NULL); window_fit(frame); /* Initial messages */ strcpy(kbd_msg, "Keyboard: key press events"); strcpy(ptr_msg, "Pointer: pointer movement events"); strcpy(but_msg, "Button: button press events"); /* Get a nice big font */ font = XLoadQueryFont(dpy = (Display *) XV_DISPLAY_FROM_WINDOW(frame), "-b&h-lucida-medium-r-normal-sans-24-240-*-*-p-*-iso8859-1"); /* Map the frame. This is normally done for us by xv_main_loop(). */ xv_set(frame, XV_SHOW, TRUE, 0); /* Get the server connection number. */ fd = XConnectionNumber(dpy); /* Make sure everything gets over to the server. */ XFlush(dpy); /* Create my own loop, only dispatching events when there is something * to dispatch. When I'm not dispatching events, I'm free to do * as I please. */ while (RUN) { FD_SET(fd, &readfds); #ifdef __linux__ timeout.tv_sec = 0; timeout.tv_usec = 250000; #endif // /* Check to see if the server has written to us. */ if (select(FD_SETSIZE, &readfds, NULL, NULL, &timeout)) { /* Read and dispatch events from the server. */ notify_dispatch(); } else { static int toggle = 0; /* Do my own thing here. Just remember not to neglect incomming * events. (*Ping the notifier as often as possible*) */ /* Erase contents of textsw. */ textsw_erase(textsw, 0, TEXTSW_INFINITY); /* Load textsw with one of two files. */ xv_set(textsw, TEXTSW_FILE_CONTENTS, toggle ? "/etc/fstab" : "/etc/passwd", TEXTSW_FIRST, 0, NULL); toggle = ~toggle; /* If I've used any X routines, be sure to flush the requests * through to the server. */ XFlush(dpy); } } /* All done. */ } /* This is called before the frame's destroy func (ie. I've interposed in * front of it. */ Notify_func my_destroy_func(frame, status) Frame frame; Destroy_status status; { if (status == DESTROY_PROCESS_DEATH || status == DESTROY_CLEANUP) RUN = FALSE; /* Now call the frame's destroy func. */ notify_next_destroy_func(frame, status); } /* * event_proc() * Called when an event is received in the canvas window. * Updates the keyboard, pointer and button message strings * and then calls repaint_proc() to paint them to the window. */ void event_proc(window, event) Xv_Window window; Event *event; { if (event_is_ascii(event)) sprintf(kbd_msg, "Keyboard: key '%c' %d pressed at %d,%d", event_action(event), event_action(event), event_x(event), event_y(event)); else switch (event_action(event)) { case KBD_USE: sprintf(kbd_msg, "Keyboard: got keyboard focus"); break; case KBD_DONE: sprintf(kbd_msg, "Keyboard: lost keyboard focus"); break; case LOC_MOVE: sprintf(ptr_msg, "Pointer: moved to %d,%d", event_x(event), event_y(event)); break; case LOC_DRAG: sprintf(ptr_msg, "Pointer: dragged to %d,%d", event_x(event), event_y(event)); break; case LOC_WINENTER: sprintf(ptr_msg, "Pointer: entered window at %d,%d", event_x(event), event_y(event)); break; case LOC_WINEXIT: sprintf(ptr_msg, "Pointer: exited window at %d,%d", event_x(event), event_y(event)); break; case ACTION_SELECT: case MS_LEFT: sprintf(but_msg, "Button: Select (Left) at %d,%d", event_x(event), event_y(event)); break; case ACTION_ADJUST: case MS_MIDDLE: sprintf(but_msg, "Button: Adjust (Middle) at %d,%d", event_x(event), event_y(event)); break; case ACTION_MENU: case MS_RIGHT: sprintf(but_msg, "Button: Menu (Right) at %d,%d", event_x(event), event_y(event)); break; default: return; } /* call repaint proc directly to update messages */ repaint_proc((Canvas)NULL, window, (Display *)xv_get(window, XV_DISPLAY), xv_get(window, XV_XID), (Xv_xrectlist *) NULL); } /* * repaint_proc() * Called to repaint the canvas in response to damage events * and the initial painting of the canvas window. * Displays the keyboard, pointer and button message strings * after erasing the previous messages. */ void repaint_proc(canvas, paint_window, dpy, xwin, xrects) Canvas canvas; /* Ignored */ Xv_Window paint_window; /* Ignored */ Display *dpy; Window xwin; Xv_xrectlist *xrects; /* Ignored */ { GC gc = DefaultGC(dpy, DefaultScreen(dpy)); XSetFont(dpy, gc, font->fid); XClearWindow(dpy, xwin); XDrawString(dpy, xwin, gc, 25, 35, kbd_msg, strlen(kbd_msg)); XDrawString(dpy, xwin, gc, 25, 65, ptr_msg, strlen(ptr_msg)); XDrawString(dpy, xwin, gc, 25, 95, but_msg, strlen(but_msg)); }