Re: Closing a Gtk::Dialog - How?



warning --- long response. please let me know if this doesn't answer your question.

Martin Schulze wrote:

Hi!

I wonder if somebody on this list can give me assistence with Gtk-Perl
and closing a Gtk::Dialog properly.

The main window in the application will create info dialog boxes on
demand which looks like the code below.

My question is how do I make the »Close«-button work properly, using
the Gtk-Perl way[tm] and witout wasting memory.

I currently know about three ways to get this done visually, but all
three of them, doesn't free memory again.


how are you closing your windows?

in your code you connect nothing to the delete_event of the Gtk::Dialog. a Gtk::Window will just ignore the delete_event if you don't connect anything to it, but a Gtk::Dialog hides.

a quick test, however, shows me that clicking a button with $dialog->destroy connected to it results in no memory leaks, but closing the Gtk::Dialog with nothing bound to its delete_event results in a resident stack size growth of 4 (k? it's the RSS column of ps) for each dialog in my really simple test.

however, adding $dialog->destroy to the delete_event handler gets rid of that leak!


in general, you ALWAYS want to bind some action to your windows' delete_events, because most users consider that *the* way to close a window, even if you have a "close" button inside! you don't have to destroy the window in the delete_event handler, just catch it.


if it's a dialog you will reuse many times, you might not want to free it at all, such that hiding and showing are suffient.


   # in init
   $dialog = undef;
   ...

   # in callback for button, key, or menuitem that opens the dialog
   if ( $dialog ) {
       # already exists, just show it again
       $dialog->show;
   } else {
       # create a new dialog
       $dialog = new Gtk::Dialog;
$dialog->signal_connect ( delete_event => sub { $dialog->hide; 1 } );
       ...
   }



otherwise, if you want it actually to go away, memory and all, then $dialog->destroy is the Right Thing.


try passing an actual reference in your callbacks instead of relying of local values in perl closures --- there might be a more subtle bug there, resulting in destroy being called on not the reference you expected. i've been bitten by that one before, and it wasn't easy to spot, because i wasn't using "strict".

that is,

       $button->signal_connect ( clicked => sub {
                                       my ($button, $win) = @_;
                                       $win->destroy;
                                       1;
                                   }, $dialog );


let me say it again:  use strict; can save your butt.


the way that i typically handle dialogs is a little more involved:


   #
   # simple function that presents the user with a question.
   #    boolean = modal_yes_no_dialog ( message, title, parent );
   # parent is optional.
   #
   sub modal_yes_no_dialog {
       my ($message, $title, $parent) = @_;

       # return value: false until proven true.
       my $ret = undef;

       my $dialog = new Gtk::Dialog;
       $dialog->set_title ( $title );

       my $label = new Gtk::Label $message;
       $label->set_padding ( 5, 5 );
       $dialog->vbox->pack_start ( $label, 1, 1, 5 );

       my $yesbn = new Gtk::Button 'Yes';
       my $nobn = new Gtk::Button 'No';
$dialog->action_area->pack_start ( $yesbn, 1, 1, 5 );
       $dialog->action_area->pack_start ( $nobn, 1, 1, 5 );

       # all ways of closing the dialog simply stop the event loop.

       # clicking Yes sets the return value to true.
$yesbn->signal_connect ( clicked => sub { $ret = 1; Gtk->main_quit; 1 } );

       # clicking No does not alter the return value.
       $nobn->signal_connect ( clicked => sub { Gtk->main_quit; 1 } );

       # make a window kill look like clicking No
$dialog->signal_connect ( delete_event => sub { Gtk->main_quit; 1 } );

       # for a bit of fanciness, make escape say No, too
       $dialog->signal_connect ( key_press_event => sub {
                               my ($window, $event) = @_;
# this value came from gdkkeysyms.h --- are there
                               # no perl constants for keysyms?
                               if ( $event->{keyval} == 0xFF1B ) {
                                   # GDK_Escape means close
                                   Gtk->main_quit;
                                   return 1 ;
                               }
                               # otherwise, pass it on
                               return 0;
                           } );

       $dialog->show_all;
       $dialog->set_transient_for ( $parent )
           if $parent;
       $dialog->set_modal ( 1 );

       # wait here for the user to clear the dialog.
       Gtk->main;

       # make sure we get rid of the window and all its memory!
       $dialog->destroy;

       # tell the caller what the user said.
       return $ret;
   }


a simple test of this code (a window with a button, each button click calls the above function, then calls ps on the process to look at the mem usage) shows no increase in size over a large number of invocations.





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