Handling Messages

Those widgets that you put into your GLADE file, in many cases, send messages to the Gtk_main loop, where they can be intercepted and acted on. It's time to add the subroutines to process them.

And before we start, there's a caution: Linux puts information "on the stack" when a subroutine is called. Global variables aren't accessible beyond one subroutine call deep, the reason being that stacks take up room and much of what is accessible to the main program isn't needed. If we got fussy about this, we would probably be better off using something like C++, which maintains a rigid structure and very tight typing. Frankly, I have found C++ and its cousin C# to be too constraining. Perhaps I don't think in a well-structured manner. Perhaps I was beaten and fed cold gruel as a child. Whatever. Give me good ol' C any time. I fell in love with pointers the moment I found out about 'em, and...

There I go again. Let's get busy with those message handlers, avoiding a few potholes as we go.

// =====HANDLERS follow========// Here are a few menu message handlers. Several aren't yet implemented.void on_file_opn_init_activate(){ // needs a dialog to load and initialize operation status // followed by an optional update of actual status}
void on_file_opn_toggle_data_acq_activate(){// code to run the function that reads/stores or pauses current operation status char str_count[50] = {0}; if(Run_data_loop) // pause data acquisition { // Get the elapsed time since the timer was started gulong API_needs_this_variable; gdouble time_elapsed = g_timer_elapsed (time_tracker, &API_needs_this_variable); gtk_label_set_text(GTK_LABEL(data_gather_label), "Data Gathering stopped"); // Report data acq elapsed time and pause the progress bar sprintf(str_count, "Data acquisition ran for %8.2lf seconds.", time_elapsed); gtk_label_set_text(GTK_LABEL(g_lbl_count), str_count); printf ("%s\n",str_count); if(data_acq_timeout_id>0) { g_source_remove(data_acq_timeout_id); data_acq_timeout_id=0; g_timer_destroy (time_tracker); //Free the memory from the timer } Run_data_loop=FALSE; } else {// resume data acquisition (make a new g_timeout_add(), tied to the // same old data acquisition call via read_raw_data() // start a new timer & loop data_acq_timeout_id=g_timeout_add(300, read_raw_data, progress_bar); time_tracker = g_timer_new (); gtk_progress_bar_pulse (GTK_PROGRESS_BAR (progress_bar)); Run_data_loop=TRUE; gtk_label_set_text(GTK_LABEL(data_gather_label), "Data Gathering restarted"); gtk_label_set_text(GTK_LABEL(g_lbl_count), "..."); }} // void on_file_opn_toggle_data_acq_activate()
void on_file_opn_save_activate(){ // needs a dialog to save operation status for next initialization printf("called on_file_opn_save_activate().\n");}
void on_file_exit_button_press_event(){ // called from menu FILE | EXIT PROGRAM selection. // needs a dialog to save operation status for next initialization printf("exiting via on_file_exit_button_press_event().\n");// digitalWrite(red, LOW); // just for fun, continued, turn off red LED// the following is unnecessary, but is here for completeness g_timer_destroy (time_tracker);// bail from program gtk_main_quit();}
//...........edit status functionsvoid on_edit_status_defaults_activate(){ printf("called on_edit_status_defaults_activate().\n");}

Here's a subroutine to set display component color

// ..................Layout Drawing display functionsvoid set_block_color(cairo_t *cr, int block_nmbr){ int status, block_pwr; status=display_data[block_nmbr].block_status;// 0=normal, 1=alarm,2=caution block_pwr=display_data[block_nmbr].block_pwr;// 0=off, 1=pack#1, 2=pack#2, // 3=siding connected to adjacent block gboolean ok_to_process; // will need to check status of adjacent blocks int next_block=block_hdwe[block_nmbr].exit_to_block_nmbr[0]; int prev_block=block_hdwe[block_nmbr].enter_from_block_nmbr[0]; // check sidings connection logic // set the block color. No effect on gap color. cairo_set_source_rgb(cr,0,0,0); // black if(alarm_display!=OFF) {switch (block_pwr) { case 1: // pack #1 cairo_set_source_rgb(cr,.5,.5,.5); // gray break; case 2: // pack #2 cairo_set_source_rgb(cr,.2,.7,.7); // blue break; case 3: // siding connected override // check sidings connection logic if((block_nmbr=8)&&(display_data[8].block_pwr!=0))block_pwr=display_data[6].block_pwr; else if((block_nmbr=9)&&(display_data[9].block_pwr!=0))block_pwr=display_data[5].block_pwr; else if((block_nmbr=10)&&(display_data[10].block_pwr!=0))block_pwr=display_data[2].block_pwr; else cairo_set_source_rgb(cr,0,0,0); // black break; default: // 0 = pwr off cairo_set_source_rgb(cr,0,0,0); // black break; } } // if(alarm_display!=OFF) // if there's an alarm or caution, override block color with it if((alarm_display==GAPS_1_BLOCK)||(alarm_display==GAPS_ADJ_BLOCKS)) { // depending on 1-block or 3 adjacent blocks ok_to_process=FALSE; if((alarm_display==GAPS_ADJ_BLOCKS) &&((display_data[block_nmbr].block_status ==display_data[next_block].block_status) ||(display_data[block_nmbr].block_status ==display_data[prev_block].block_status))) // center of 3 blocks {ok_to_process=TRUE;} if((alarm_display==GAPS_1_BLOCK) &&(display_data[next_block].block_status>0) &&(display_data[prev_block].block_status>0)) // center of 3 blocks {ok_to_process=TRUE;} switch(status) { case 1: // alarm// uses enum alarm_display {OFF, GAPS_ONLY, GAPS_1_BLOCK, GAPS_ADJ_BLOCKS}; if(ok_to_process==TRUE) { cairo_set_source_rgb(cr,1,0,0);} // RED break; case 2: // caution if(ok_to_process==TRUE) { cairo_set_source_rgb(cr,.8,.8,0);} // yellow break; default: // actually case 0 = normal break; } // switch() } // if((alarm_display==GAPS_1_BLOCK)||...} // void set_block_color()

Now for some meat! Here's a general subroutine for displaying block direction, followed by a message handler for each track electrical block. Notice that, in each block's handler subroutine, we pass a pointer to the widget rather than its value. This avoids the problem of having to access a data structure two levels or more deep.

// ..............block direction handlers...................int handle_all_direction_labels(GtkLabel *dir_label){ const gchar * state, *new_state; int code; char *format, *format_bkgnd; gchar *markup, *markup_bkgnd; int x; state=gtk_label_get_text(dir_label); x=strcmp("<fwd", state); if(x==0){new_state="rev>";code=1;} x=strcmp("fwd>", state); if(x==0){new_state="<rev";code=1;} x=strcmp("rev>", state); if(x==0){new_state="<fwd";code=0;} x=strcmp("<rev", state); if(x==0){new_state="fwd>";code=0;} format="<span foreground=\"#000000\">%s</span>"; // black format_bkgnd="<span background=\"#eeeeee\">%s</span>"; // kinda white markup=g_markup_printf_escaped(format,new_state); markup_bkgnd=g_markup_printf_escaped(format_bkgnd,new_state); gtk_label_set_text( dir_label, new_state); gtk_label_set_markup(dir_label, markup); gtk_label_set_markup(dir_label, markup_bkgnd); return code;} // int handle_all_direction_labels(GtkLabel *dir_label)
// OOPS! Wired up the block fwd/rev relay addresses backward!void on_block_01_direction_button_press_event() // receives 0 for fwd, 1 for rev{ display_data[1].block_direction=handle_all_direction_labels(label_ptr_array[1].block_direction_ptr); display_data[1].block_direction_changed=TRUE; if(display_data[1].block_direction) {write_pin(ADDRESS22,06,on_invert);} // rev else{write_pin(ADDRESS22,06,off_invert);} // fwd}
void on_block_02_direction_button_press_event(){ display_data[2].block_direction=handle_all_direction_labels(label_ptr_array[2].block_direction_ptr); display_data[2].block_direction_changed=TRUE; if(display_data[2].block_direction) {write_pin(ADDRESS22,05,on_invert);} // rev else{write_pin(ADDRESS22,05,off_invert);} // fwd}

And so on for the rest of the main track blocks, 00 through 07. Next, do the power packs. We don't want the power to be switched too fast, which might short the packs if connected to each other wrong. (We use a common-wire configuration.) Thus, we'll use software to force the packs to switch OFF between ON assignments.

// ....................Block Power Pack SELECTION/OFF modal window functions......int block_power_pack_choose(GtkLabel *pwr_label){// printf("called block_power_pack_choose().\n"); int response; GtkWidget *dialog; GtkBuilder *builder; const gchar * current_state, *new_state; char *format; gchar *markup;// Pop up a small window containing pack selection buttons. builder = gtk_builder_new_from_file("../window_main7.glade"); dialog = GTK_WIDGET(gtk_builder_get_object (builder, "pwr_dialog_win")); // set transient via Glade response = gtk_dialog_run(GTK_DIALOG(dialog));current_state=""; current_state=gtk_label_get_text(pwr_label);if(response!=0) // skip on "cancel" button {int x=strcmp("pwr #1", current_state); if(x==0) // ignore choice button {new_state="pwr off"; format="<span foreground=\"#999999\">%s</span>"; markup=g_markup_printf_escaped(format,new_state); r esponse=3; // change to pwr pack #1 off// turn off block relay// set pwrpack selection relay to pack #1 (not energized?) } x=strcmp("pwr #2", current_state); if(x==0) // ignore choice button { new_state="pwr off"; format="<span foreground=\"#999999\">%s</span>"; markup=g_markup_printf_escaped(format,new_state); response=1; // change to pwr pack #2 off// turn off block relay// set pwrpack selection relay to pack #1 anyway (not energized?) } x=strcmp("pwr off", current_state); // MUST BE OFF to turn on a power pack if(x==0) {switch(response) {case 4: // pack #1 new_state="pwr #1"; format="<span foreground=\"#000000\">%s</span>"; markup=g_markup_printf_escaped(format,new_state);// set pwrpack selection relay to pack #1 (not energized?)// then turn on block relay break; case 2: // pack #2 new_state="pwr #2"; format="<span foreground=\"#40c0c0\">%s</span>"; markup=g_markup_printf_escaped(format,new_state);// set pwrpack selection relay to pack #2 (energized?)// then turn on block relay break; default: // pwr off new_state="pwr off"; format="<span foreground=\"#999999\">%s</span>"; markup=g_markup_printf_escaped(format,new_state);// turn off block relay// set pwrpack selection relay to pack #1 anyway (not energized?) } } gtk_label_set_text(pwr_label, new_state); gtk_label_set_markup(pwr_label, markup); } gtk_widget_destroy(dialog); g_object_unref(G_OBJECT(builder));return response; // 0=no_change, 4=#1 on, 3=#1 off, 2=#2 on, 1=#2 off}
// ................Block Power Pack SELECTION/OFF handlers...............
void block_pwr_button_store(int blk_nmbr, int stat)// given: blk_nmbr= block number (selected via display)// stat= 0=no_change, 4=#1 on, 3=#1 off, 2=#2 on, 1=#2 off // needs to set block on/off relay, pwr pack select relay such that // 0=off, 1=pack#1, 2=pack#2, 3=siding connected to adjacent block // switches block on/off to OFF when pwr pack selection is switched{ switch(stat) { case 0: // no action break; case 1: // block off, #1 default selected write_pin(ADDRESS21,block_relay.block_on_off_pin[blk_nmbr],off); // block select off write_pin(ADDRESS21,block_relay.pwr_select_pin[blk_nmbr],off); // #2 default not selected display_data[blk_nmbr].block_pwr=0; //raw_detector_data[blk_nmbr].block_pwr_changed=TRUE; break; case 2: // block on, #2 selected write_pin(ADDRESS21,block_relay.block_on_off_pin[blk_nmbr],on); // block select on write_pin(ADDRESS21,block_relay.pwr_select_pin[blk_nmbr],on); // #2 selected on display_data[blk_nmbr].block_pwr=2; // pack #2 connected display_data[blk_nmbr].block_pwr_changed=TRUE; break; case 3: // block off, #1 default selected write_pin(ADDRESS21,block_relay.block_on_off_pin[blk_nmbr],off); // block select off write_pin(ADDRESS21,block_relay.pwr_select_pin[blk_nmbr],off); // #1 default selected display_data[blk_nmbr].block_pwr=0; display_data[blk_nmbr].block_pwr_changed=TRUE; break; case 4: // block on, #1 default selected write_pin(ADDRESS21,block_relay.block_on_off_pin[blk_nmbr],on); // block select on write_pin(ADDRESS21,block_relay.pwr_select_pin[blk_nmbr],off); // #1 defaulted on display_data[blk_nmbr].block_pwr=1; // pack #1 connected display_data[blk_nmbr].block_pwr_changed=TRUE; break; default: // no action break; }}

Now for the message handler subroutines. These were specified in your GLADE work.

void on_block_01_pwr_button_press_event() // responds to return values: // returned: 0=no_change, 4=#1 on, 3=#1 off, 2=#2 on, 1=#2 off // needs to set // 0=off, 1=pack#1, 2=pack#2, // 3=siding connected to adjacent block{ int blk_nmbr=01; int stat=block_power_pack_choose(label_ptr_array[blk_nmbr].pwr_label_ptr); block_pwr_button_store(blk_nmbr,stat); // sets raw_data[block_nmbr, return_code].block_pwr_changed; if((stat==1)||(stat==3)) { on_block_10_pwr_button_press_event(); // siding on_block_13_pwr_button_press_event(); // siding }}
void on_block_02_pwr_button_press_event(){ int blk_nmbr=02; int stat=block_power_pack_choose(label_ptr_array[blk_nmbr].pwr_label_ptr); block_pwr_button_store(blk_nmbr,stat); }

...and so on for blocks 00 through 07. Note that they use the pointers stored in the setup code in main() to point to the correct widget.

Sidings connect to the track block that they branch off of, so they are handled a little bit differently. They are wired to the adjacent track block's electrical circuitry, and must be set up via this software so that the adjacent block must be energized before they can be turned on. This avoids a "surprise" when a track block is turned on, a locomotive is sitting on a siding, and it unexpectedly gets energized.


// Entries for sidings. Set 'em by toggling CONNECTED or PWR OFF with change flag set// Logic: check also in set_block_color().void siding_pwr_button_store( int block_nmbr, int main_blk_nmbr, gboolean force_off){ // if main block is off, disconnect. force_off turns siding off const gchar * state; state=gtk_label_get_text(label_ptr_array[block_nmbr].pwr_label_ptr); char * x=strstr(state,"off"); if ((display_data[main_blk_nmbr].block_pwr==0)||(x==NULL)||(force_off)) // main block off,or "off" not found { write_pin(ADDRESS20,block_relay.block_on_off_pin[block_nmbr],off); display_data[block_nmbr].block_pwr=0; display_data[block_nmbr].block_pwr_changed=TRUE; gtk_label_set_text( label_ptr_array[block_nmbr].pwr_label_ptr, "pwr off"); printf("block %i OFF, pin %i, (main_block %i)\n",block_nmbr,block_relay.block_on_off_pin[block_nmbr],main_blk_nmbr); } else { write_pin(ADDRESS20,block_relay.block_on_off_pin[block_nmbr],on); display_data[block_nmbr].block_pwr=display_data[main_blk_nmbr].block_pwr; display_data[block_nmbr].block_pwr_changed=TRUE; gtk_label_set_text( label_ptr_array[block_nmbr].pwr_label_ptr, "pwr ON"); printf("block %i ON, pin %i, (main_block %i)\n",block_nmbr,block_relay.block_on_off_pin[block_nmbr],main_blk_nmbr); }} // siding_pwr_button_store()
void on_block_08_pwr_button_press_event(){ // Toggle siding to whatever status block 06 is, or off siding_pwr_button_store(8, 6, FALSE);}
void on_block_09_pwr_button_press_event(){ // Toggle siding to whatever status block 05 is, or off siding_pwr_button_store(9, 5, FALSE); // following statements "bounce" the setting// if ((raw_data[9].block_pwr==1)||(raw_data[9].block_pwr==3)||(raw_data[9].block_pwr==0)) // lead-in siding off,or "off" not found// { siding_pwr_button_store(9, 5, TRUE);// }}
void on_block_10_pwr_button_press_event(){ // Toggle siding to whatever status block 01 is, or off siding_pwr_button_store(10, 1, FALSE);}// extra_siding_ptr handlersvoid on_block_11_pwr_button_press_event(){ // Toggle siding to whatever status block 06 is, or off siding_pwr_button_store(11, 6, FALSE);}
void on_block_12_pwr_button_press_event(){ // Toggle siding to whatever status block 05 is, or off siding_pwr_button_store(12, 5, FALSE);}
void on_block_13_pwr_button_press_event(){ // Toggle siding to whatever status block 010 is, or off if ((display_data[10].block_pwr==1)||(display_data[10].block_pwr==3)) { siding_pwr_button_store(13, 1, FALSE);} else { siding_pwr_button_store(13, 1, TRUE);} // mandatory OFF}

There are two levels of power pack control. One, here, toggles train power to any or all track blocks. Individual block off/on relays are handled further below.

// .................two power packs: ON/OFF switches.............gboolean on_switch_pwr_1_state_set(){// printf("on_switch_pwr_1_state_set() pressed\n");// if(gtk_switch_get_state((GtkSwitch *)switch_pwr_1)) if(gtk_switch_get_state(switch_ptr_array.switch_pwr_1)) {// printf("switch_pwr_1 is OFF\n"); switch_ptr_array.main_pwr_1=FALSE; // Set this power pack OFF and update the data array entry write_pin(ADDRESS20,017,off); } else {// printf("switch_pwr_1 is ON\n"); // Set this power pack ON and update the data array entry switch_ptr_array.main_pwr_1=TRUE; write_pin(ADDRESS20,017,on); } return FALSE;}
gboolean on_switch_pwr_2_state_set(){// printf("on_switch_pwr_2_state_set() pressed\n"); if(gtk_switch_get_state(switch_ptr_array.switch_pwr_2)) {// printf("switch_pwr_2 is OFF\n"); // Set this power pack OFF and update the data array entry switch_ptr_array.main_pwr_2=FALSE; write_pin(ADDRESS20,016,off); } else {// printf("switch_pwr_2 is ON\n"); // Set this power pack ON and update the data array entry switch_ptr_array.main_pwr_2=TRUE; write_pin(ADDRESS20,016,on); } return FALSE;}

Next, we set some indicators. These don't actually control anything, but they can be set by clicking on them. Why, you may ask? Well, you may want to take a block out of service or indicate that an attached siding is in use. ...not really sure, but if I come up with a need for this capability, it's available.

// ................STATUS handlers...............int handle_all_status_labels(GtkLabel *status_label, int shortcut)// shortcut is set to desired state: 0==normal,1=alarm,2=caution. // Set to -1 to skip shortcut.{ const gchar * state, *new_state; char *format, *format_bkgnd; gchar *markup, *markup_bkgnd; int ret_code;//printf("handle_all_status_labels() called with shortcut=%i\n",shortcut); state=gtk_label_get_text(status_label); if(shortcut>=0) state="XXXXX"; // for shortcut, get current state out of the way int x=strcmp("Normal", state); //printf("state=%s; x=%i",state,x); if((x==0)||(shortcut==1)) { new_state="alarm"; format="<span foreground=\"#000000\">%s</span>"; // black markup=g_markup_printf_escaped(format,new_state); format_bkgnd="<span background=\"#ff0000\">%s</span>"; // red markup_bkgnd=g_markup_printf_escaped(format_bkgnd,new_state); ret_code=1; } x=strcmp("alarm", state); //printf(", %i",x); if((x==0)||(shortcut==2)) { new_state="caution"; format="<span foreground=\"#000000\">%s</span>"; // black markup=g_markup_printf_escaped(format,new_state); format_bkgnd="<span background=\"#c0c000\">%s</span>"; // yellow markup_bkgnd=g_markup_printf_escaped(format_bkgnd,new_state); ret_code=2;//printf("shortcut= %i, state %s\n",shortcut, state); } x=strcmp("caution", state); if((x==0)||(shortcut==0)) { new_state="Normal"; format="<span foreground=\"#000000\">%s</span>"; // black markup=g_markup_printf_escaped(format,new_state); format_bkgnd="<span background=\"#ffffff\">%s</span>"; // white markup_bkgnd=g_markup_printf_escaped(format_bkgnd,new_state); ret_code=0; } gtk_label_set_text( status_label, new_state); gtk_label_set_markup(status_label, markup); gtk_label_set_markup(status_label, markup_bkgnd);// Set this block's relay and data array entry in process_layout_data_for_display() return ret_code; // 0=normal, 1=alarm,2=caution}
void on_status_label_01_button_press_event() // Stores block_status as 0=normal, 1=alarm,2=caution. // shortcut=-1 means process what's on screen. direct set 0=normal,1=alarm,2=caution{display_data[1].block_status=handle_all_status_labels(label_ptr_array[1].status_label_ptr,-1);}
void on_status_label_02_button_press_event(){display_data[2].block_status=handle_all_status_labels(label_ptr_array[2].status_label_ptr,-1);}

How do we handle siding access? Well, this is a work in progress. At the moment, I think it might be a good approach if the operator requests access to a siding and the computer's response depends on if things are correct electrically, the turnout is aligned properly, and the siding is not already fully occupied. This one is also a work in progress.

// xover_siding_permitgboolean handle_all_permit_labels(GtkLabel *label_ptr, int block_nmbr,gboolean xover) // FALSE for siding, TRUE for xover{ char *format, *format_bkgnd; const gchar *state; gchar *markup, *markup_bkgnd; gboolean ret_code, status; state=gtk_label_get_text(label_ptr); status=display_data[block_nmbr].permit_status;// if(xover){new_state="take siding";}// else{new_state="crossover";}printf("handle_all_permit_labels():state=%s, status[%i]=%i\n",state,block_nmbr,status); if(status) // TRUE = okay to enter; { // toggle to FALSE = do NOT enter format="<span foreground=\"#000000\">%s</span>"; // black markup=g_markup_printf_escaped(format,state); format_bkgnd="<span background=\"#eeeeff\">%s</span>"; // bluish markup_bkgnd=g_markup_printf_escaped(format_bkgnd,state); ret_code=FALSE; } else { // toggle to TRUE = okay to enter format="<span foreground=\"#000000\">%s</span>"; // black markup=g_markup_printf_escaped(format,state); format_bkgnd="<span background=\"#ffff00\">%s</span>"; // yellow markup_bkgnd=g_markup_printf_escaped(format_bkgnd,state); ret_code=TRUE; }// gtk_label_set_text( label_ptr, state); gtk_label_set_markup(label_ptr, markup); gtk_label_set_markup(label_ptr, markup_bkgnd); return ret_code; // TRUE = permit okay}
void on_siding_08_button_press_event() // take siding{ // FALSE for siding, TRUE for xover display_data[8].permit_status=display_data[11].permit_status =handle_all_permit_labels(permit_array[0].label_ptr,8,FALSE);}
void on_siding_09_button_press_event() // take siding{ display_data[9].permit_status=display_data[12].permit_status =handle_all_permit_labels(permit_array[1].label_ptr,9,FALSE);}
void on_siding_10_button_press_event() // take siding{ display_data[10].permit_status=display_data[13].permit_status =handle_all_permit_labels(permit_array[2].label_ptr,10,FALSE);}

There are similar concerns for crossovers. Are the electrical needs satisfied and turnouts aligned properly? ...another work in progress. ...continued computer and model railroad fun!

void on_crossover_0201_button_press_event() // take crossover{ display_data[2].permit_status=display_data[1].permit_status =handle_all_permit_labels(permit_array[3].label_ptr,2,TRUE);}
void on_crossover_0506_button_press_event() // take crossover{ display_data[5].permit_status=display_data[6].permit_status =handle_all_permit_labels(permit_array[4].label_ptr,5,TRUE);}
void on_crossover_0605_button_press_event() // take crossover{ display_data[6].permit_status=display_data[5].permit_status =handle_all_permit_labels(permit_array[5].label_ptr,6,TRUE);}

The following is a radio button group which allows the operator to specify what amount of alarm display options he or she wants to see. "...bells & whistles!"

// Set alarm display mode.// uses enum alarm_display {OFF, GAPS_ONLY, GAPS_1_BLOCK, GAPS_ADJ_BLOCKS};void on_click_alarm_gaps_only() {alarm_display=GAPS_ONLY;}void on_click_alarm_gaps_block() {alarm_display=GAPS_1_BLOCK;}void on_click_alarm_gaps_adjoin() {alarm_display=GAPS_ADJ_BLOCKS;}void on_click_alarm_off() {alarm_display=OFF;}

Every good application has a HELP access and an ABOUT screen. Help isn't stable enough, but ABOUT is, although minimally so. Here, we're set to handle it.

// ....................ABOUT added dialogvoid on_help_about_activate(){ printf("called on_help_about_activate().\n");// int response; GtkWidget *dialog; GtkBuilder *builder;
builder = gtk_builder_new_from_file("yesno_dialog.ui"); dialog = GTK_WIDGET(gtk_builder_get_object (builder, "dialog1"));// gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(user_data));// gtk_window_set_transient_for (GTK_WINDOW(dialog), NULL);gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(global_window_main));// gtk_widget_show_all(dialog);// response = gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); g_object_unref(G_OBJECT(builder));// g_print ("Response is %s\n", response == 1 ? "Yes" : "No");}
void on_about_box_button_button_press_event(__attribute__((unused)) GtkMenuItem *item, gpointer user_data){ printf("Calling on_about_box_button_button_press_event().\n");}void on_about_box_button_destroy(){ // need to somehow use gtk_widget_destroy(GTK_WIDGET(about_... printf("trying to exit about box via on_about_box_button_destroy().\n");}

There are some peripheral needs that should be met. One is a test of whatever is currently under development. At the moment, it's an occupancy sensing test, and as of this writing, the software isn't complete and the boards aren't hooked up. it's very much a work in progress. Here's one way of implementing a test setup so you can interact with the program. I'm sure you'll be modifying it. (I plan to, just as soon as I can polish up this website a bit.)

// .................main window controls (menu functions located above)// Called when "increment" button is clicked. // Increments Block # for occupancy test. -1 = no test// Legal block #'s: 00 thru 07.void on_btn_increment_clicked() // FOR TESTING ONLY{ static unsigned int count = -2; int j;//,earlier; char str_count[50] = {0}; gtk_label_set_text(GTK_LABEL(g_lbl_hello), "Block Occupancy Test"); for(j=0;j<=7;j++){detector_buffer[j].block_occupied=FALSE;} count++; if(count>7) { count=-1; sprintf(str_count, "Block %d (no test)", count); } else { sprintf(str_count, "Block %d (-1 for no test)", count); detector_buffer[count].block_occupied=TRUE; if(long_train_test)// problem if block was entered by other than entrance #0 {detector_buffer[block_hdwe[count].enter_from_block_nmbr[0]].block_occupied=TRUE;} else // problem if block was entered by other than entrance #0 {detector_buffer[block_hdwe[count].enter_from_block_nmbr[0]].block_occupied=FALSE;} } gtk_label_set_text(GTK_LABEL(g_lbl_count), str_count);} // void on_btn_increment_clicked()
// select if test-train is longer than one blockvoid on_check_long_train(GtkToggleButton *togglebutton, gpointer user_data){ //printf("long-train test clicked\n"); if (gtk_toggle_button_get_active(togglebutton)) { long_train_test=TRUE; // g_print("Option is Checked\n"); } else { long_train_test=FALSE; // g_print("Option is Unchecked\n"); }} // void on_check_long_train()

This last is traditionally included in GTK windowing code. I don't think you need it, but I don't have the heart to deleted it, just because I'd have to re-write it if it turns out later that it's needed.

// ..................Redundant? used to be called when window is closedvoid on_window_main_destroy(){ printf("exiting via on_window_main_destroy().\n"); gtk_main_quit(); turn_all_relays_off(); // reset all relays to OFF}

It's optional reading, but you can click here to see an APPENDIX titled "Initializing Data Arrays" for my particular layout