[ Pobierz całość w formacie PDF ]
.**/XtAddEventHandler( aLabel, ButtonPressMask, FALSE, downMouse, NULL);XtAddEventHandler( aLabel, ButtonMotionMask, FALSE, moveMouse, NULL);XtAddEventHandler( aLabel, ButtonReleaseMask | LeaveWindowMask,FALSE, upMouse, NULL);/***** Call the function "bye" when the PushButton receives*** an activate message; i.e.when the pointer is moved to*** the button and Button1 is pressed and released.**/XtAddCallback( aButton, XmNactivateCallback, bye, (XtPointer) NULL);XtRealizeWidget(top);XtAppMainLoop(app);return(0);}void bye(Widget w, XtPointer clientdata, XtPointer calldata){exit(0);}Managing the QueueManaging the X server is critical if you have to handle lots of incoming events.The XtAppMainLoop() function handles all the incoming events via the following functions:XtAppPending checks the queue to see if any events are pending.XtAppNextEvent removes the next event from the queue.XtDispatchEvent passes the message to the appropriate window.The loop can do something else between checking and removing messages via the replacement code segment:while (!done){while (XtAppPending( applicationContext)){XtAppNextEvent( applicationContext, &ev));XtDispacthEvent( &ev));}done = interEventFunction();}There are some caveats with this scheme:This is a nonblocking function.It must be fed at all times with events, or it will take over all other applications' time.There is no guarantee when your inter-event function will be run if the queue is flooded with events.Note the while loop for checking messages.It's more efficient to flush the queue first and then call your function rather than calling it once every time you check for messages.The inter-event function must be fast or you will see the user interface slow down.If you want to give some response back to your user about what's going on while in a long inter-event function, you can make a call to XmUpdateDisplay( Display *).Thiswill handle only the Expose events in the queue so that you can update some status display.Consider using the select call to handle incoming events of file descriptors.This is a call that enables an application to wait for events from various file descriptors on read-ready, write-ready, or both.The file descriptors can be sockets, too!See the man page for more information on the select call.Open all the files with an open call.Get the file descriptor for the event queue.Use the Select macros to set up the parameters for select call ret = return from the select function:switch (ret)case 0:process the event queuecase 1:.process the file descriptorWork ProceduresThese are functions called by the event-handler loop whenever no events are pending in the queue.The function is expected to return a Boolean value indicating whether it has to be removed from the loop after it is called.If TRUE, it wants to beremoved; if FALSE, it wants to be called again.For example, you could set up a disk file transfer to run in the background, which will keep returning FALSE until it is done, at which time it will return TRUE.The work procedures are defined asBoolean yourFunction(XtPointer clientdata);The way to register a work procedure is to callXtWorkProcId XtAppAddWorkProc ( XtAppContext app,XtWorkProc functionPointer,XtPointer clientData);The return ID from this call is the handle to the work procedure.It is used to remove the work procedure with a call to the function XtRemoveWorkProc( XtWorkProcId id);.Using TimeoutsA timeout is used to perform some task at (almost) regular intervals.Applications set up a timer callback function that is called when a requested time interval has passed.This function is defined asvoid thyTimerCallback( XtPointer clientdata, XtInterval *tid);where clientdata is a pointer to client-specific data.The setup function for the timeout returns the timer ID and is defined asXtIntervalId XtAddTimeOut ( XtAppContext app,int milliseconds,XtTimerCallback TimerProcedure,XtPointer clientdata);This call sets up a timer to call the TimerProcedure function when the requested milliseconds have passed.It will do this only once.If you want cyclic timeoutsfor example, in a clock applicationyou have to explicitly set up the nextfunction call in the timer handler function itself.So generally, the last line in a timer handler is a call to set a timeout for the next time the function wants to be called.Linux is not designed for real-time applications, and you can't expect a deterministic time interval between successive timer calls.Some heavy graphics updates can cause delays in the timer loop.For user-interface applications, the delays are probablynot a big drawback; however, consult your vendor before you attempt to write a time-critical control application.Depending on your application, your mileage may vary.See Listing 32.15 for an example of setting up cyclic timers.Listing 32.15.Setting up cyclic timers./*** This application shows how to set a cyclic timer*/#include <X11/Intrinsic.h>#include <Xm/Xm.h>#include <Xm/Form.h>#include <Xm/PushB.h>#include <Xm/Text.h>int counter;char buf[32];#define ONE_SECOND 1000L /* **APPROXIMATELY** 1000 milliseconds.*//* Timing is *not* precise in Motif.so do not rely on this time** for a time-critical application.Use interrupt handlers instead.*/void makeTimer(Widget w, XtIntervalId id);void bye(Widget w, XtPointer clientdata, XtPointer calldata);int main(int argc, char **argv){Widget top;XtAppContext app;Widget aForm;Widget aText;Widget aButton;Arg args[5];/***** Initialize the toolkit.**/top = XtAppInitialize(&app, "KBH", NULL, 0, (Cardinal *)&argc,argv, NULL, args, 0);/***** Create a Form on this top-level Widget.This is a nice Widget*** to place other Widgets on top of.**/aForm = XtVaCreateManagedWidget("Form1",xmFormWidgetClass, top,XmNheight,90,XmNwidth,200,NULL);/***** Add a button on the form you just created.Note how this Button*** Widget is connected to the form that it resides on.Only*** left, right, and bottom edges are attached to the form.The*** top edge of the button is not connected to the form.**/aButton = XtVaCreateManagedWidget("Push to Exit",xmPushButtonWidgetClass, aForm,XmNheight,20,XmNleftAttachment,XmATTACH_FORM,XmNleftOffset,20,XmNrightAttachment,XmATTACH_FORM,XmNrightOffset,20,XmNbottomAttachment,XmATTACH_FORM,NULL);/***** Now let's create the label for us.*** The alignment is set to right-justify the label.*** Note how the label is attached to the parent form.**/aText = XtVaCreateManagedWidget("This is a Label",xmTextWidgetClass, aForm,XmNalignment, XmALIGNMENT_CENTER,XmNleftAttachment,XmATTACH_FORM,XmNrightAttachment,XmATTACH_FORM,XmNtopAttachment,XmATTACH_FORM,XmNbottomAttachment,XmATTACH_WIDGET,XmNbottomWidget,aButton,NULL);/***** Now add the timer handler**/counter = 0;makeTimer(aText, (XtIntervalId )NULL);/***** Call the function "bye" when the PushButton receives*** an activate message; i.e.when the pointer is moved to*** the button and Button1 is pressed and released.**/XtAddCallback( aButton, XmNactivateCallback, bye, (XtPointer) NULL);XtRealizeWidget(top);XtAppMainLoop(app);return(0);}void bye(Widget w, XtPointer clientdata, XtPointer calldata){exit(0);}/** This function creates the timer code
[ Pobierz całość w formacie PDF ]