motifdeveloper.com
Sponsored by IST Limited
Formerly MW3: Motif on the World Wide Web [MW3 Logo]
Last Updated
November 18, 2002
 


X-Designer - The Leading X/Motif GUI Builder - Click to download a FREE evaluation
 

motifdeveloper.com
Home
About the site
Bulletin Board
News Archive
OpenGroup News
Events
Search
Frequently Asked Questions
The Motif FAQ
X/Motif FAQs
General FAQs
Ask Antony
Latest Q & A
All Q & As
Submit Question
Tips & Pointers
Code Examples
Software
OpenMotif
Widget Sets
GUI Toolkits & Libraries
Motif suppliers
Non-commercial S/W
Commercial Software
Multimedia
Miscellaneous
Organizations
Docs & Pubs
X/Motif Newsgroups
Security
Internationalization
Feedback
Feedback Form
Contributors
 

How do I arrange for a Text widget to display the system time?

8-Aug-01 16:00 GMT

How do I arrange for a Text widget to display the system time?

Question: We have to display system time on a TextField widget. How can i solve this problem?

This can be done using an Xt TimerCallbackProc, registered with the toolkit by XtAppAddTimeOut().

Firstly, some notes on timers, so-called synthetic events, and event handling in general.

The XtAppContext, and Event Handling

Associated with the XtAppContext structure are a set of queues for handling events of various types. There is a queue for handling Work procedures (registered by XtAppAddWorkProc()), a queue for handling Input procedures (registered through XtAppAddInput()), a queue for handling TimeOut procedures (registered through XtAppAddTimeOut()), a queue for handling Signals (registered by XtAppAddSignal()), and so forth.

If you are unfamiliar with these routines, a Work procedure is an application-defined function which you can arrange to have called whenever there are no user-events on the X queue. It is used for idle-time background processing. An Input procedure is an application routine which processes input on a pipe or other file descriptor in such a way that the handling of data reception does not interfere with other events going on in the X system. Similarly, a Signal procedure is a way of handling the processing of asynchronous signals so that the X queue mechanisms are not interrupted at critical moments. Lastly, a TimeOut procedure, the one we will consider in detail below, is the means whereby an application can set up handlers designed to go off at specific intervals in the future, such that the handling of the event again does not interfere with critical X queue processing.

The XtAppContext event handling mechanisms check the state of the synthetic event queues, as well as the normal X event queue, whenever a request is made to process the current state of the event queues. In other words, when the application issues the request to process the next event, the toolkit looks not just to see if there are any user X events, but also to see if any timer has gone off, if any signal has arrived, or if there is data pending on an Input queue. This is where XtAppNextEvent()/XtAppProcessEvent() differ from the lower level Xlib routines (XNextEvent(), and so forth). If you hand write your X event handling loop such that you avoid the XtApp* routines, then any timer/work/ signal or input routines you have registered with the toolkit will simply fail to be processed.

If you want to use XtAppAddTimeOut() or any of the other related synthetic event mechanisms, you are therefore forced to use the XtAppContext-parametered Xt event handling routines (or the Xt routines which use a default XtAppContext internally if you do not create your own specific XtAppContext structure). This means that your event mechanisms are constrained to use XtAppMainLoop(), or XtAppNextEvent(), XtAppProcessEvent() at certain specific points in the application event handling. This does not mean to say that you cannot use XNextEvent() and so forth at specific points in your application if there are certain effects you require, just that if you want your timers handled, they are only handled correctly if you call the right event handling routines at the right time, and not by the lower level Xlib routines.

TimeOut Procedures

A TimeOut procedure is, as already specified, an application-defined routine which is called after a specific time interval. TimeOut procedures are registered with the toolkit using the routine XtAppAddTimeOut(), formally specified as follows:

    XtIntervalId XtAppAddTimeOut(XtAppContext        app_context,
				 unsigned long       timeout_period,
				 XtTimerCallbackProc timeout_handler,
				 XtPointer           call_data)

The app_context parameter is an XtAppContext, an opaque handle onto a structure created by XtCreateApplicationContext(), or returned from XtAppInitialize() and related routines. Basically, it is a structure originally designed to coordinate the memory of multiple X applications in platform environments which do not fully support independent multiple address spaces; the structure had its points, so became a general repository of X application control information.

The timeout_period parameter specifies a time interval, measured in milliseconds, after which the application-defined routine timeout_handler is to be invoked.

The timeout_handler parameter is the application-defined routine: it is what you want called when the timeout period expires. What it does is entirely application specific; we will present a simple handler below which updates a text widget with the current system time.

The XtIntervalId returned value is an opaque type: it is a handle onto the structure which is registered with the toolkit. Its only use as far as the application is concerned is so that the request to call an application routine at some point in the future can be cancelled. To cancel the timeout, simply call XtRemoveTimeOut(), passing as parameter the XtIntervalId returned from XtAppAddTimeOut():

    XtIntervalId id = XtAppAddTimeOut(app_context, ....) ;

    ...

    /* Changed our minds: timer no longer needed */
    XtRemoveTimeOut(id) ;

A TimeOut procedure, or more formally an XtTimerCallbackProc, has the following signature:

    void (*XtTimerCallbackProc)(XtPointer client_data, XtIntervalId *id)

The first parameter is the client_data, which is anything application-specific you want passed to the routine. This is the same as whatever you pass as the fourth parameter to the XtAppAddTimeOut() call. For example:

    extern XtAppContext app_context ;
    extern Widget       text ;

    void my_timer(XtPointer client_data, XtIntervalId *id)
    {
	...
    }

    ...

    XtIntervalId *id = XtAppAddTimeOut(app_context,
				       (unsigned long) 1000, /* milliseconds */
				       my_timer,
					  (XtPointer) text) ;

Polling

The first thing to understand is that a call to XtAppAddTimeOut() does not arrange for our application routine to be called every n milliseconds; it only arranges for the application function to be called once after the period expires. If you want regular or repeated polling, you have to arrange to call the routine again. This means a subsequent call to XtAppAddTimeOut(), generally insides the TimeOut routine, so that it sets itself up for the subsequent call. A function which was to be called every second would therefore have the following architecture:

    extern XtAppContext app_context ;

    void my_looping_timer(XtPointer client_data, XtIntervalId *id)
    {
	/* Do the application-specific functionality */
	...

	/* Go round again in 1 second, same parameters */

	XtAppAddTimeOut(app_context, (unsigned long) 1000, my_looping_timer, \
							client_data) ;
    }

The Example

Given a Motif Text component (XmText or XmTextField), we can update the component to display the system time as follows:

  • We define an XtTimerCallbackProc which fetches the current clock tick, converts it to a string, and inserts the result in the Text.
  • We arrange that this routine is called every second.
  • We call this routine as soon as the Text is created anyway, so that it is seeded with the system time first up.

Firstly, the XtTimerCallbackProc. Assume that we pass the Text component concerned as client data to the routine; time() and ctime() are standard C library routines:

    #include <time.h>

    extern XtAppContext app_context ; /* Or whatever you call yours                */
    extern Widget       text ;        /* Where you want to display the system time */

    void show_system_time(XtPointer client_data, XtIntervalId *id)
    {
	Widget text        = (Widget) client_data ; /* Where we write the system time */
	long   system_tick = time((long *) 0) ;     /* Get the system clock tick */
	char  *cptr        = ctime(&system_tick) ;  /* Convert to string */
	char   buffer[32] ;

	/* Convert the system time to whatever format you require   */
	/* Here, I just blat it out without conversion. Beware that */
	/* ctime() returns a pointer to static storage.             */

	(void) sprintf(buffer, "%s", cptr) ;

	/* Write the result to the Text widget               */
	/* This works for either XmText or XmTextField       */
	/* NB: XmTextFieldSetString() doesnt work for XmText */

	XmTextSetString(text, buffer) ;

	/* Now arrange to call ourselves again in 1 second */

	XtAppAddTimeOut(app_context,
		       (unsigned long) 1000, /* milliseconds */
		       show_system_time,
		       client_data) ;
    }

This sets up the looping and displaying part. We need to initialize the loop with a first call when the text widget is created. There are two ways of doing this. We can either set up a Timer which goes off straight away:

    Widget text = XmCreateTextField(...) ;

    XtAppAddTimeOut(app_context,
		   (unsigned long) 0,
		   show_system_time,
		   (XtPointer) text) ;

Or we can simply call the handler directly ourselves:

    Widget text = XmCreateTextField(...) ;

    show_system_time((XtPointer) text, (XtIntervalId *) 0) ;

Notes

Timers in Xt cannot be used as an atomic clock. You can expect some interference with normal X queue event processing, with whatever network delays this may involve, such that you cannot guarantee an exact concurrence between the dispatch of your handler and the requested timeout interval. This does not mean to say that TimeOut procedures are hopelessly inaccurate - all things being equal, expect the error to be measured in a few milliseconds; what you might need to do, however, is to check the system clock periodically and adjust the next timeout period accordingly to avoid creeping slippage if you need something which is regularly accurate. Also to be borne in mind is the fact that the XtAppNextEvent() routine processes Input procedures before TimeOut handlers; if you have an Input procedure registered, and its operation is expensive, then a pending TimeOut handler will slip by the duration of the Input handler.

[We avoided this issue in the example, by simply calling time() inside the TimeOut handler: the system tick we display is as current as possible, even though it may happen to be somewhat over a second since the previous call of the handler, depending on circumstances.]

Attempting to remove a TimeOut procedure (XtRemoveTimeOut()), when the TimeOut handler to which the XtIntervalId pertains has already been called, is unstable. You do not have to unregister if your handler has already fired - it is removed from the queue automatically; just make sure that you do not remove a timer that has already gone off or a core dump is the likely result. If you are caching the XtIntervalId globally for cases where you do need to remove a timer, make sure that the timer internally resets the XtIntervalId so that XtRemoveTimeOut() has no nasty side effects:

    XtIntervalId myId = XtAppAddTimeOut(..., my_timer, ...)

    ...

    void my_timer(XtPointer client_data, XtIntervalId *id)
    {
	    myId = (XtIntervalId) 0 ;
	    ...
    }

    ...

    if (myId != (XtIntervalId) 0) {
		XtRemoveTimeOut(myId) ;
    }

Bibliography

For a good general-purpose introduction to Events, Event Processing, the following is recommended: in particular, Chapter 12 covers the ground given in the text above:

    Advanced Motif Programming Techniques,
    Alistair George and Mark Riches,
    Prentice Hall,
    ISBN: 0-13-219965-3
    Unfortunately this book is out of print,
    but you may be able to buy it from Amazon.com
    

For reference materials on the routines mentioned in the text, the following are recommended:

    X Toolkit Intrinsics Programming Manual,
    Adrian Nye and Tim O'Reilly,
    O'Reilly and Associates,
    ISBN: 0-937175-34-X
    Buy it from Amazon.com or Amazon.co.uk

    X Toolkit Intrinsics Reference Manual,
    Edited by David Flanaghan,
    O'Reilly and Associates,
    ISBN: 1-56592-007-4
    Buy it from Amazon.com or Amazon.co.uk

    Xlib Reference Manual,
    Edited by Adrian Nye,
    O'Reilly and Associates,
    ISBN: 1-56592-006-6
    Buy it from Amazon.com or Amazon.co.uk

 



Sponsored by X-Designer - The Leading X/Motif GUI Builder - Click to download a FREE evaluation

 

Goto top of page

 

[IST Limited]
IST Limited is the
proud sponsor of motifdeveloper.com.
 

Thanks to all the contributors to these pages.

Privacy Policy

 
"Motif" is a registered trademark of The Open Group. All other trademarks are the property of their respective owners.

Some articles/papers here have their own copyright notice. All other information is copyright ©1999-2008 IST Limited

[CommerceOne] MW3 site originally by Ken Sall of Commerce One (formerly Century Computing).