#include #include #include #include "../tlmplib/tlmplib.h" #include "tlmpdia.h" #include #include #include #include using namespace std; // #Specbeg: editrecords / sample /* Here is a typical/simple application. */ static void samples_editrecords(int nb) { int nb; glocal.nb = nb; ("records","Some records",help_nil); newf_head ("ID\tDescription\tDate"); for (int i=0; i xconf_notice ("Editing record %d",no); } // #Specend: // #Specbeg: editrecords / sample / sorted /* Here is a typical/simple application showing column sorting. */ static void samples_editrecords_sorted(int nb) { int nb; glocal.nb = nb; ("records","Some sortable records",help_nil); newf_head ("ID\tDescription\tDate"); sortable(); // We sort each colums independantly (no useful) SSTRINGS nums,descs,dates; for (int i=0; isetfromf ("This is record %d",i); descs.add (s); s = new SSTRING; s->setfromf ("%02d/10/2000",i); dates.add (s); } if (order != SORT_NONE){ switch (column){ case 0: nums.sort(); break; case 1: descs.sort(); break; case 2: dates.sort(); break; }; if (order == SORT_DESC){ nums.invert(); descs.invert(); dates.invert(); } } for (int i=0; iget(),"%s\t%s" ,descs.getitem(i)->get(),dates.getitem(i)->get()); } xconf_notice ("Editing record %d",no); if (state.leftb){ selectsort (head); }else if (state.rightb){ // Contextual menu xconf_notice ("Put a popup here"); } } // #Specend: // #Specbeg: sample / uithread / principles /* Sometime we which to have two dialogs at once (consider the FRAMEWORK component if you wish to do that). The uithread function is handy but the uithread TLMP component is easier to handle. It triggers up to 3 threads and waits for their completion. As such is allows the various threads to share glocal, */ static void sample_dialog(const char *title) { DIALOG dia; SSTRING s; dia.newf_str ("field1",s); dia.edit (title,"",help_nil); } static void sample_uithread() { (); sample_dialog("dialog thread1"); sample_dialog("dialog thread2"); sample_dialog("dialog thread3"); xconf_notice ("All threads done"); } // #Specend: // #Specbeg: sample / uithread / updating a dialog /* The following example grab the information produced by a process and fill a table (editrecord). One uithread is used to collect the data and a PRIVATE_MESSAGE is used to signal the editrecord thread. This sample also show how one thread may ask another to end using PRIVATE_MESSAGE. */ static void sample_uithread_popen() { glocal SSTRINGS data; glocal PRIVATE_MESSAGE samples,ending; dialog_clear(); (); ("/tmp/x output 100",1,true); /* We are using diagui_sync() to make sure the other dialog are still alive. */ int ret = diagui_sync (pop,timeout,true); if (dialog_testmessage(glocal.ending)){ end = true; pop.kill(); } return ret; glocal.data.add (new SSTRING(line)); dialog_sendmessage (glocal.samples); ("Some records","",help_nil); waitfor (glocal.samples); newf_head ("column1\tcolumn2\tcolumn3"); setvsize (10); for (int i=0; iget(); char tmp[strlen(s)+1]; strcpy (tmp,s); char *pt = tmp; while (*pt != '\0'){ if (*pt == ' ') *pt = '\t'; pt++; } SSTRING word; pt = str_copyword (word,tmp); new_menuitem (word.get(),pt); } printf ("Line %d was selected\n",no); dialog_sendmessage (glocal.ending); } // #Specend: /* Function used by the preceding example. It generates a new line every 2 seconds. */ static void sample_output (int nb) { for (int i=0; i static void sample_fork( const char *arg, PRIVATE_MESSAGE &msg, bool &cmd, int &progress, PRIVATE_MESSAGE &progress_msg) { fprintf (stderr,"Starting\n"); glocal SHAREMEM a; glocal bool *cmd = &cmd; glocal int *progress = &progress; glocal PRIVATE_MESSAGE *progress_msg = &progress_msg; fprintf (stderr,"Starting sharemem done\n"); // We are doing an nslookup on a name. This may time out glocal const char *name = arg; (1,msg); fprintf (stderr,"Sync with the parent\n"); join(0); fprintf (stderr,"Sync done\n"); struct hostent *ent = gethostbyname(glocal.name); if (ent == NULL){ glocal.a.p.found = false; }else{ glocal.a.p.found = true; glocal.a.p.addr[0] = ent->h_addr[0]; glocal.a.p.addr[1] = ent->h_addr[1]; glocal.a.p.addr[2] = ent->h_addr[2]; glocal.a.p.addr[3] = ent->h_addr[3]; } fprintf (stderr,"%d seconds so far\n",duration); (*glocal.progress)++; dialog_sendmessage(*glocal.progress_msg); glocal.a.p.duree = duration; if (duration > 100) end = true; fprintf (stderr,"Some message cmd=%d\n",*glocal.cmd); if (*glocal.cmd){ kill(); } fprintf (stderr,"The child is joining\n"); if (glocal.a.p.found){ fprintf (stderr,"Name found addr=%d.%d.%d.%d\n" ,glocal.a.p.addr[0] ,glocal.a.p.addr[1] ,glocal.a.p.addr[2] ,glocal.a.p.addr[3]); }else{ fprintf (stderr,"Name not found\n"); } } static void sample_fork(const char *arg) { // We repeat 5 time to test for various resources leaks for (int i=0; i<5; i++){ glocal PRIVATE_MESSAGE msg; glocal const char *arg = arg; glocal bool cmd = false; glocal PRIVATE_MESSAGE done; glocal PRIVATE_MESSAGE progress_msg; glocal int progress = 0; (); DIALOG dia; dia.newf_chk ("Terminate",glocal.cmd,"nslookup"); int gauge = dia.size(); dia.newf_gauge ("Duration",glocal.progress,40); dia.waitfor (glocal.done); dia.waitfor (glocal.progress_msg); while (1){ MENU_STATUS code = dia.edit ("Click a button","",help_nil); if (code == MENU_CANCEL){ break; }else if (code == MENU_MESSAGE){ if (dialog_testmessage(glocal.done)){ break; }else if (dialog_testmessage(glocal.progress_msg)){ dia.reload(gauge); } }else{ dialog_sendmessage (glocal.msg); } } sample_fork (glocal.arg,glocal.msg,glocal.cmd ,glocal.progress,glocal.progress_msg); dialog_sendmessage(glocal.done); } } // #Specend: // #Specbeg: sample / formtmp component / fault /* The following example shows one usage of forktmp(). Since it is easy to communicate between a child and a parent using SHAREMEM, it is convenient to shield a program from a potentially sensitive part. Or said differently, all program have bugs, so by isolating various area, the core of the program may continue to operate even if a child fail (segfault). While this does not seem clean (bug should be fixed, no ?), building software against its own flaws may be a solution sometime. The following example shows a simple tasks which immediatly segfault. It presents the default behavior of the failed functag. */ static void sample_forkfault() { (); char *pt = NULL; *pt = '\0'; } // #Specend: int main (int argc, char *argv[]) { int ret = (argc, argv,"linuxconf"); fprintf (stderr,"/tmp/x records\n"); fprintf (stderr,"/tmp/x records-sorted\n"); fprintf (stderr,"/tmp/x tree\n"); fprintf (stderr,"/tmp/x uithread\n"); fprintf (stderr,"/tmp/x uithreadpopen\n"); fprintf (stderr,"/tmp/x fork\n"); fprintf (stderr,"/tmp/x forkfault\n"); if (argc < 1){ usage(); }else if (strcmp(argv[0],"records")==0){ samples_editrecords(15); }else if (strcmp(argv[0],"records-sorted")==0){ samples_editrecords_sorted(15); }else if (strcmp(argv[0],"uithread")==0){ dialog_clear(); sample_uithread(); }else if (strcmp(argv[0],"uithreadpopen")==0){ sample_uithread_popen(); }else if (strcmp(argv[0],"output")==0){ sample_output (atoi(argv[1])); }else if (strcmp(argv[0],"fork")==0){ dialog_clear(); sample_fork (argv[1]); }else if (strcmp(argv[0],"forkfault")==0){ dialog_clear(); sample_forkfault (); }else if (strcmp(argv[0],"tree")==0){ /* This sample code evolved to test edittree and the treemenu widget in the GUI. Maybe less and less relevant. It shows how the set_lookup() function may be used to connect editone event easily. */ glocal int nb = 3; glocal set are_set; // Those must be highlited glocal set nb_set; // We must increase the number of child glocal set are_del; // This node is deleted (not chown anymore) ("tree","This is a tree",help_nil); for (int i=0; i<3; i++){ char buf[100]; sprintf (buf,"root-%d",i); if (glocal.are_del.count(buf)==0){ new_file (buf); set_lookup(buf); } } for (int i=0; i0){ setnexttagged(); } new_subdir (buf); set_lookup (buf); for (int j=0; j<2; j++){ sprintf (buf,"dir%d.%d",i,j); if (glocal.are_del.count(buf)==0){ if (glocal.are_set.count(buf)>0){ setnexttagged(); } new_subdir (buf); set_lookup (buf); int nbk = 2; if (glocal.nb_set.count(buf)>0) nbk = 4; for (int k=0; k0){ setnexttagged(); } new_file (buf); set_lookup(buf); } } end_subdir(); } } end_subdir (); } } if (uistate.shiftkey){ if (glocal.are_set.count(key)>0){ glocal.are_set.erase(key); }else{ glocal.are_set.insert(key); } }else if (uistate.ctrlkey){ if (glocal.nb_set.count(key)>0){ glocal.nb_set.erase(key); }else{ glocal.nb_set.insert(key); } }else if (uistate.rightb){ // Once deleted, there gone, no way to undelete them glocal.are_del.insert(key); }else{ xconf_notice ("Editing record %s level %d key=%s",spath,level,key); } }else{ usage(); } return 0; return ret; }