Two GTK apps not behaving properly together, why?



Hi, can someone help me out here with this "small" problem?

I have two apps, both use GTK, and one calls the other, kinda like a
parent/child thing and communicate via FIFOs. The parent one is very
simple at the mo', it's been built to purely test the functionality of
the child which is what I am mainly developing ATM.

The child when launched, forks so GTK runs separately, (you may have
seen my earlier postings about threading GTK apps, this seems to work),
and the child can still read the FIFOs and do other stuff. Any new
windows to be made are signalled via a private pipe to the GTK 'thread'.

Currently the only signals are:

+ SIG_ABOUT - bring up an 'about' box
+ SIG_QUIT  - Get the GTK 'thread' to quit

Here's the problem:

If I launch the child on it's own, and signal SIG_ABOUT, it works, the
about box pops up and I can close it, etc.

If I launch the child via the parent, either by a 'fork & exec( "child" 
)' or 'system( " child &" )' then the parent window pops up OK.

The parent window just has two buttons, one to get the child to send a
SIG_ABOUT, the other button to get the child to quit.

When I click the about button for the first time, nothing happens, when
I click it again, a window pops up, but it's blank. Then window does
seem to have the widgets on it because if I click where a button
should be, ( around the Bottom-right ), it acts accordingly.

Then when I click the quit button on the parent, I suddenly get the
second instance of the window pop up, ( blank ), and disappear again
with all the other windows as both apps close down.

I can't work out what is going wrong, can anyone shed some light here...

I've tested this under gtk+-1.2.0 on Linux 2.2.4, and gtk+-1.0.6 on
Solaris 2.5, and I get the same behaviour.

Here is the code, (cut down quite heavily):

PARENT:

int main( int argc, char *argv[] );
void about_callback( GtkWidget *widget, gpointer data );
void quit_callback( GtkWidget *widget, gpointer data );

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

  ...
  
  pid = fork();
  
  if( pid > 0 ) {

      ...

      gtk_init( &argc, &argv );
      
      window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
      
      gtk_signal_connect( GTK_OBJECT( window ), "destroy", GTK_SIGNAL_FUNC( gtk_exit ), NULL );
      gtk_signal_connect( GTK_OBJECT( window ), "delete_event", GTK_SIGNAL_FUNC( gtk_exit ), NULL );
      
      box = gtk_vbox_new( TRUE, 5 );
      
      button = gtk_button_new_with_label( "About" );
      
      gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( about_callback ), NULL );
      
      gtk_box_pack_start( GTK_BOX( box ), button, TRUE, TRUE, 5 );
      
      button = gtk_button_new_with_label( "Quit" );
      
      gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( quit_callback ), NULL );
      
      gtk_box_pack_start( GTK_BOX( box ), button, TRUE, TRUE, 5 );
      
      gtk_container_add( GTK_CONTAINER( window ), box );
      
      gtk_widget_show_all( window );
      
      gtk_main();
      
    }

    comm_finish( input_fifo );
    comm_finish( output_fifo );
  } else {
    
    execl( "../plugins/localfs/localfs", "localfs", "/tmp/arse1", "/tmp/arse2", ( char * ) 0 );
  }
  
  return 0;
}

void about_callback( GtkWidget *widget, gpointer data ) {
  
  new_command.code = ABOUT;
  new_command.arg_len = 0;
  
  comm_send( output_fifo, &new_command, sizeof( command ) );
}

void quit_callback( GtkWidget *widget, gpointer data ) {
  
  new_command.code = TERMINATE;
  new_command.arg_len = 0;
  
  comm_send( output_fifo, &new_command, sizeof( command ) );
  
  gtk_main_quit();
}

NOTE: comm_send is basically a wrapper for write with a little error
checking.

CHILD:

int signal_pipe[2];

int main( int argc, char *argv[] );
void signal_handler( void *arg, int fd, GdkInputCondition cond );
void handle_signal( char c );
void send_signal( display_signal sig );

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

  if( argc == 3 ) {
    
    pipe( signal_pipe );
    pid = fork();
    
    if( pid > 0 ) {
      
      close( signal_pipe[0] );

      ...

      comm_receive( input_fifo, &new_command, sizeof( command ) );

      while( new_command.code != TERMINATE ) {
	
	switch( new_command.code ) {

	  ...

	  case ABOUT : {
	  
	    send_signal( SIG_ABOUT );
	    
	    break;
	  }
	  
          ...

	}
	
	comm_receive( input_fifo, &new_command, sizeof( command ) );
      }

      send_signal( SIG_QUIT );

      ...
      
    } else {
      
      close( signal_pipe[1] );
      gtk_init( &argc, &argv );
      gdk_input_add( signal_pipe[0], GDK_INPUT_READ, signal_handler, NULL );
      gtk_main();
      
      return SMF_OK;
    }
  }
}

void signal_handler( void *arg, int fd, GdkInputCondition cond ) {
  
  int n;
  char sig;
  
  while( 1 ) {
    
    n = read( fd, &sig, 1 );
    
    if( n <= 0 ) {
      
      break;
    }
    
    handle_signal( sig );
  }
}

void handle_signal( char c ) {
  
  display_signal sig = ( display_signal ) c;
  
  switch( sig ) {
    
    case SIG_ABOUT : {
      
      /* Display an about box I suppose
       */
      about_box();
      break;
    }
    case SIG_QUIT : {
      
      /* Quit GTK
       */
      gtk_main_quit();
      break;
    }
  }
}

void send_signal( display_signal sig ) {
  
  char c = ( char ) sig;
  
  write( signal_pipe[1], &c, 1 );
}

NOTE: about_box() just calls a function that displays an about box,
nothing complicated, just a window with a label and a button.

That's the pair of 'em, with any unnecessary stuff removed.

If someone could please tell me what I'm doing wrong, I'd be very
grateful, I have three weeks to finish this project and this has me
stumped.

Matt



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]