Gary D Stewart - 2009-06-15

Well, its been a while since my last message (I just recently checked and I see
that the message window overlap that I reported (long ago) has been fixed.
THANKS !). I've been busy doing other projects and I'm just now getting back
to this one. This is actually the last problem I encountered before stopping
work on this project and I first noticed it in OTK 0.75. I just rechecked it
and I am seeing the problem in 0.87. I'm getting segmentation faults when
using the close "X" on the message window with a registered kill window
callback function when the pointer parameter I pass to it is dereferenced as
shown in the print out and code below. I could have multiple message windows
open (some without user intervention) so I use the MessageWindow structure to
store information that allows the code that opened the window to see if any
push button action has taken place, and for the push button callback handlers
or the code that opened the window to close the correct window when needed. It
is also used to prevent the same message window from being opened more than
once. I've traced around to see what was happening and this is what happens
when I run it and use the window close "X":

[gdstew@localhost PCTM_demo]$ ./PCTM_demo

Using OTK - V0.87

open_message_window() OtkWidget: 0x840ef68

Otk_RegisterWindowKillEventFunction() OtkWidget: 0x840ef68
Otk_RegisterWindowKillEventFunction() callback param: (nil)

open_message_window() OtkWidget: 0x83dcbe0

Otk_RegisterWindowKillEventFunction() OtkWidget: 0x83dcbe0
Otk_RegisterWindowKillEventFunction() callback param: 0x80774d0

display_command_err_message() MesgWin: 0x80774d0
display_command_err_message() OtkWidget: 0x83dcbe0

open_message_window(), command error MesgWin: 0x80774d0

kill_mesg_window() MesgWin: 0x804d170
kill_mesg_window() OtkWidget: 0x4c7085d

Segmentation fault

As you can see, everything looks good until it enters the kill window callback
handler and then the MessageWindow pointer is different. I might be missing
something, but I don't think so.

Once again, if you could look into this it will be greatly appreciated. Thanks.

// *****************************************************************************
// *
// * Structure used to pass information between the message window handler and
// *  the function that opened the window.
// *
// *****************************************************************************

struct MessageWindow
  {
    bool wait_flag ; // Wait for a message window push button press flag
    int pb_pressed ; // Which push button was pressed in the message window
    OtkWidget OtkW_window ; // Otk widget for opened message window
  } ;

typedef struct MessageWindow *MesgWin ;

// *****************************************************************************
// *
// * Description:  Message window close "X" pushed handler
// *
// * Parameters:  mw_p - pointer to MessageWindow structure for window with
// *
// *
// * Notes:   
// *
// *****************************************************************************

static void  kill_mesg_window(void *mw_p)
{
   MesgWin  mesg_win_p ;

     mesg_win_p = (MesgWin) mw_p ;

#ifdef SEGFAULT_PROB

     printf("\nkill_mesg_window() MesgWin: %p\n", mesg_win_p) ;
     printf("kill_mesg_window() OtkWidget: %p\n\n", mesg_win_p->OtkW_window) ;

#endif // SEGFAULT_PROB

     if (mesg_win_p != NULL)
       {
         mesg_win_p->wait_flag = false ; // Clear wait for button push flag
         mesg_win_p->pb_pressed = KILL_PB ; // Kill window button pushed
         mesg_win_p->OtkW_window = NULL ; // Window no longer in use
       }
}

// *****************************************************************************
// *
// * Description:  This opens a message window on top of all existing windows
// *                an prints the selected message.
// *
// * Parameters:  mesg_class - selects which class of messages the message
// *                            belongs to
// *              mesg_number - selects which message in the message class to
// *                             print
// *              param_1 - pointer to first data to display when needed
// *              param_2 - pointer to second data to display when needed
// *
// * Returns:  pointer to MessageWindow structure for opened window
// *
// *****************************************************************************

MesgWin  open_message_window (int_32 mesg_class, int_32 mesg_number, void *param_1, void *param_2)
{
   float  y = 5.0 ;

   OtkWidget  mesg_win ;

   static struct  MessageWindow m_win ;
   MesgWin  mesg_win_p ;

     mesg_win = OtkMakeWindow(Otk_Recessed, Otk_Blue, Otk_LightGray, 10.0, 10.0, 70.0, 85.0) ;

#ifdef SEGFAULT_PROB

     printf("open_message_window() OtkWidget: %p\n", mesg_win) ;

#endif // SEGFAULT_PROB

     Otk_Set_Text_Aspect(0.4);

     switch (mesg_class)
       {
         case USAGE_MESG:

           mesg_win_p = display_usage_message(mesg_win) ;

           break ;

         case DEVICE_INIT_MESG:

           mesg_win_p = display_dev_init_err_message(mesg_win, mesg_number, (bool) param_1) ;

           break ;

         case DEVICE_IO_ERROR_MESG:

           mesg_win_p = display_dev_io_err_message(mesg_win, mesg_number) ;

           break ;

         case COMMAND_ERROR_MESG:

           mesg_win_p = display_command_err_message(mesg_win, mesg_number) ;

#ifdef SEGFAULT_PROB

           printf("open_message_window(), command error MesgWin: %p\n", mesg_win_p) ;

#endif // SEGFAULT_PROB

           break ;

         case RESPONSE_ERROR_MESG:

           mesg_win_p = display_response_err_message(mesg_win, mesg_number) ;

           break ;

         ... More case statements and default

       }

     Otk_Set_Text_Aspect(1.0) ;
     return (mesg_win_p) ;
}

// *****************************************************************************
// *
// * Description:  Displays protocol level send command error messages
// *
// * Parameters:  mw - pointer to OTK widget for this window
// *              message_number - Selects which send command error message to
// *                                display
// *
// * Returns:  pointer to MessageWindow structure for opened window
// *
// *****************************************************************************

static MesgWin  display_command_err_message(OtkWidget mw, int_32 message_number)
{
   float  y = 5.0, dy = 12.0,  dy1_5 = 15.0 ;

   OtkWidget  ok_pb1, ok_pb2, exit_pb ;

   static struct  MessageWindow m_win1, m_win2, m_win3, m_win4, m_win5 ;

     switch (message_number)
       {
         case Q_FULL:

           if (m_win1.OtkW_window == NULL)
             {
               m_win1.wait_flag = true ;
               m_win1.pb_pressed = NO_PB ;
               m_win1.OtkW_window = mw ;

               Otk_RegisterWindowKillEventFunction(mw, kill_mesg_window, (void *) &m_win1) ;
             }
           else
             {
               Otk_RemoveObject(mw) ; // Free the unused message window Otk widget

               return (NULL) ;
             }

           OtkMakeTextLabel(mw, "Command queue is full", Otk_Black, 3.0, 1.0, 4.0, y) ;

           ok_pb1 = OtkMakeButton(mw, 40.0, 75.0, 20.0, 15.0, "", ok_pb_cb, (void *) &m_win1) ;
           OtkMakeTextLabel(ok_pb1, "OK", Otk_Black, 3.0, 1.0, 30.0, 15.0) ;

           return (&m_win1) ;

           break ;

         ... More case statements

         case PCTM_DISCONNECTED:

           if (m_win4.OtkW_window == NULL)
             {
               m_win4.wait_flag = true ;
               m_win4.pb_pressed = NO_PB ;
               m_win4.OtkW_window = mw ;

               Otk_RegisterWindowKillEventFunction(mw, kill_mesg_window, (void *) &m_win4) ;
             }
           else
             {
               Otk_RemoveObject(mw) ; // Free the unused message window Otk widget

               return (NULL) ;
             }

#ifdef SEGFAULT_PROB

           printf("display_command_err_message() MesgWin: %p\n", &m_win4) ;
           printf("display_command_err_message() OtkWidget: %p\n\n", mw) ;

#endif // SEGFAULT_PROB

           OtkMakeTextLabel(mw, "Attempting to connect to the", Otk_Black, 3.0, 1.0, 4.0, y) ;
           y = y + dy ;
           OtkMakeTextLabel(mw, " PCTM", Otk_Black, 3.0, 1.0, 4.0, y) ;

           exit_pb = OtkMakeButton(mw, 40.0, 75.0, 20.0, 15.0, "", exit_werr_pb_cb, (void *) &m_win4) ;
           OtkMakeTextLabel(exit_pb, "Exit", Otk_Black, 3.0, 1.0, 25.0, 15.0) ;

           return (&m_win4) ;

           break ;

         ... More case statements and default

       }
}

// *****************************************************************************
// *
// *  otk_lib.c slightly modified to print pointers of interest
// *
// *****************************************************************************

void Otk_RegisterWindowKillEventFunction( OtkWidget topobj, void (*callback)(void *x), void *parameter )
{

printf("\nOtk_RegisterWindowKillEventFunction() OtkWidget: %p\n", topobj) ;
printf("Otk_RegisterWindowKillEventFunction() callback param: %p\n\n", parameter) ;

if ((topobj->parent != 0) && (topobj->superclass == Otk_SC_WindowPane)) topobj = topobj->parent;
topobj->callback = callback;
topobj->callback_param = parameter;
}

P.S. FYI, I am developing a fairly sophisticated demonstration program for some
      hardware that I designed that communicates over a USB "serial interface"
      or regular serial port. This involves low level I/O so I am doing a good
      deal of error checking during debugging and this can open error message
      windows. The hardware uses a simple protocol of sending a command, and
      waiting for a response (or timeout) with data that will be displayed
      using one of the OTK gadgets and text for multiple sensors each with
      their own window that is updated at a maximum rate of once per second.
      A higher level protocol automatically retries on non-critical errors.
      Either of these can open protocol error messages. Plus, there are several
      main window pull down menu bars that can generate commands and responses
      to display/modify hardware options and display hardware status. Eventually
      I intend to block all but the critical error messages unless a debug mode
      is enabled.

P.S.P.S On the main page of your on-line documentation this line:

          The following are related functions:    <a name="#anch7a">

        works a lot better if it is changed to:

          The following are related functions:    <a name="anch7a">

       I maintain an offline version of the on-line documentation if you or
        anybody else is interested.