[XForms] client event sample application

Jeff wd4nmq at comcast.net
Sat Apr 3 01:42:42 EST 2004


Below is an appliaction that uses the fl_register_client_callback() and 
demonstrates why atoms are needed. As asked for by Angus I believe.

A quick explanation on why atoms are needed.
When a client callback is called, all it gets is a pointer to an XEvent 
structure and all it knows is it is a ClientMessage. It has no idea how 
the data is formatted. This is where an atom comes into play. An atom is 
registered with the XInternAtom() call. This atom is then put into 
effect for the whole X display, like 0:0. Now, any app or thread running 
in display 0:0 can use that atom.

In my demo below I have a text widget that the time is displayed in. The 
actual time is read from the system in a thread. The time is sent as 
either a long, or as a pointer to a time struct. These alternate every 
second.

Now, to demonstate how atoms are used I create two atoms, timeStructAtom 
& longTimeAtom. if the time data is a long, longTimeAtom is used. If it 
is a pointer to time struct, timeStructAtom is used. Now the client 
callback can decide how the time is encoded and act appropiatly to 
display it.

Remember, there can be only ONE user ClientMessage callback for an app. 
So atoms are important in letting the callback know how the data is 
formatted.

The code:

#include "forms.h"
#include <stdlib.h>
#include "timeEvent.h"
#include <time.h>
#include <pthread.h>

Atom           longTimeAtom, timeStructAtom;
pthread_t   getTimeThread;

FD_testEvent *fd_testEvent;

FD_testEvent *create_form_testEvent(void)
{
  FL_OBJECT *obj;
  FD_testEvent *fdui = (FD_testEvent *) fl_calloc(1, sizeof(*fdui));

  fdui->testEvent = fl_bgn_form(FL_NO_BOX, 420, 250);
  obj = fl_add_box(FL_UP_BOX,0,0,420,250,"");
  fdui->timeText = obj = fl_add_text(FL_NORMAL_TEXT,30,90,350,60,"");
    fl_set_object_boxtype(obj,FL_SHADOW_BOX);
    fl_set_object_lsize(obj,FL_HUGE_SIZE);
    fl_set_object_lalign(obj,FL_ALIGN_LEFT|FL_ALIGN_INSIDE);
  fl_end_form();

  fdui->testEvent->fdui = fdui;

  return fdui;
}
/*---------------------------------------*/

FL_CLIENT_CALLBACK clientCallback(FL_FORM *form, XEvent *xev){
 
  char  line[128];

// Use message_type to decide how time is encoded

  if(xev->xclient.message_type == longTimeAtom){
        fl_set_object_label(fd_testEvent->timeText,
                ctime(&xev->xclient.data.l[0]));
  }
  else if(xev->xclient.message_type == timeStructAtom){
    strftime(line,128, "%a %b %d %H:%M:%S %Y",xev->xclient.data.l[0]);
    fl_set_object_label(fd_testEvent->timeText, line);
   
  }

}

/*******************************************/

int timerThread(void *ptr){

  time_t the_time;
  struct tm *tm_ptr;
  XEvent xev;

  sleep(3); // long timeout first time

    while(1){
      the_time = time((time_t *)0);
      if(the_time & 0x0001){
    xev.xclient.type = ClientMessage;
    xev.xclient.window = fl_get_winID(fd_testEvent->testEvent);
    xev.xclient.message_type = longTimeAtom;
    xev.xclient.format = 16;
    xev.xclient.data.l[0] = the_time;
      }
      else {
    tm_ptr = localtime(&the_time);
    xev.xclient.type = ClientMessage;
    xev.xclient.window = fl_get_winID(fd_testEvent->testEvent);
    xev.xclient.message_type = timeStructAtom;
    xev.xclient.format = 16;
    xev.xclient.data.l[0] = (long)tm_ptr;
      }
      XSendEvent(fl_display,
         fl_get_winID(fd_testEvent->testEvent),
                   False, 0l, &xev);
      sleep(1);
    }
}

/*************************************/

int main(int argc, char *argv[])
{
  int  rtn;

   fl_initialize(&argc, argv, 0, 0, 0);
   fd_testEvent = create_form_testEvent();

   longTimeAtom = XInternAtom(fl_display, "Long Time", FALSE);
   timeStructAtom = XInternAtom(fl_display, "Time Pointer", FALSE);
   fl_register_client_callback(fd_testEvent->testEvent, clientCallback);
   /* fill-in form initialization code */

   /* show the first form */
   fl_show_form(fd_testEvent->testEvent,FL_PLACE_CENTERFREE,
        FL_FULLBORDER,"testEvent");
  rtn = pthread_create(&getTimeThread,
                       NULL,
                       (void *) timerThread,
                       NULL);
   fl_do_forms();
   return 0;
}
// End of code

Now, since the code to update the time widget is running in the gui code 
space, and not the thread actually getting the time. There are no 
conflicts for the internal xforms code to write the form. You can use 
fl_do_forms() instead of fl_check_forms() and have to have mutexes for 
threads to be able to update a form. I believe this is much cleaner.

Well, it's 1:30 am local and I am hitting the sack.

Jeff



More information about the Xforms mailing list