Perl Gtk2::Window->list_toplevels

97 views Asked by At

I'm using Perl Gtk2, and I want to see the list of open toplevel windows, using:

my @WL = Gtk2::Window->list_toplevels;
print STDOUT "TOP_WINDOWS:\n @WL\n";
TOP_WINDOWS: 
Gtk2::Window=HASH(0x23a4040) Gtk2::Window=HASH(0x23b5628) Gtk2::Window=HASH(0x1ca6238)

When I dump this list:
print STDOUT "DUMPER:\n", Dumper (@WL);
... it yields this:
DUMPER:
$VAR1 = bless( {}, 'Gtk2::Window' );
$VAR2 = bless( {}, 'Gtk2::Window' );
$VAR3 = bless( {}, 'Gtk2::Window' );

How do I process the above bless objects/value? I'm looking to get the name (or some kind of unique indicator) of each of the top_level window.

FOLLOW-UP QUSTION: The following doesn't work for "state" when I have additional widgets inside the toplevel - I got to believe I'm simply missing something here!

sub SM_callback ()
{
 my ($button, $data) = @_;

 my $DS       = $$data[0];
 my $hostname = $$data[1]; 

 state $DW;
 if ( ! $DW )
 { 
  $DW = Gtk2::Window->new('toplevel');
  $DW->set_default_size(400, 200);
  $DW->set_title($hostname);

  my $VB = Gtk2::VBox->new( 0, 0 );
  $DW->add($VB);

  my $TB = Gtk2::TextBuffer->new();
  $TB->set_text($hostname);

  my $TV = Gtk2::TextView->new_with_buffer($TB);

  my $SW = Gtk2::ScrolledWindow->new( undef, undef );
  $SW->add($TV);

  $VB->add($SW);

  $DW->show_all;
 }
 else
 {
  $DW->present;
 }

}
2

There are 2 answers

0
CraigP On BEST ANSWER

Here's my final solution:

By looping thru the list_toplevels in call_back funct, and if top_level window is already opened (or minimized) via checking get_name, then present it, otherwise create the new top_level window (and set_name for future checking).

#!/usr/bin/perl
# PURPOSE: Trying to determine how to recognize which toplevel window
#          is open to avoid opening same toplevel window muliple times.

use warnings;
use strict;
use feature qw(say state);
use Data::Dumper;
use Gtk2 -init;

#######################################################################
sub BN_callback 
{
 my ($button, $dataref) = @_;
 my $widget_name = $$dataref[0];

 my @open_TLW = Gtk2::Window->list_toplevels;

 foreach my $w ( @open_TLW )
 {
  my $open_name = $w->get_name;
  if ( $open_name eq $widget_name )
  {
   $w->present;
   return;
  } 
 }

 my $DW = Gtk2::Window->new('toplevel');
    $DW->set_default_size(400, 200);
    $DW->set_title($widget_name." sigtest_file");
    $DW->set_name($widget_name);
    $DW->show_all;
}
#######################################################################

my $TL = Gtk2::Window->new('toplevel');
   $TL->set_default_size(400, 200);
   $TL->set_position('center');
   $TL->set_name('Main_Window');
   $TL->signal_connect('delete-event' => sub { Gtk2->main_quit });
   $TL->show_all;

my $VB = Gtk2::VBox->new( 0, 0 );

$TL->add($VB);

my @BN = qw/BUTTON1 BUTTON2/;
foreach my $bn ( @BN )
{
 my $BT = Gtk2::Button->new($bn);
    $BT->set_name($bn); 
    $BT->signal_connect(clicked =>  \&BN_callback, [$bn]);

 $VB->add($BT);
}

$TL->show_all;
Gtk2->main;
1
zdim On

The list_toplevels method returns the list of Gtk2::Window (or here) objects. Browse the docs to see the kinds of methods/idetifiers that are available for toplevel windows, what you seek.

Developed from the synopsis of Gtk2

use warnings;
use strict;
use feature 'say';

use Gtk2 -init;

my $window = Gtk2::Window->new('toplevel');
$window->set_default_size(400, 200);
$window->set_position('center');
$window->set_name('main');
$window->set_title('Main Window');
my $button = Gtk2::Button->new('Quit');
$button->signal_connect(clicked => sub { Gtk2->main_quit });
$window->add($button);
$window->show_all;

my $win2 = Gtk2::Window->new('toplevel');
$win2->set_default_size(100, 200);
$win2->set_name('side');
$win2->set_title('== side window ==');
my $bt2 = Gtk2::Button->new('Hello');
$win2->add($bt2);
$win2->show_all;

my @tl_wins = Gtk2::Window->list_toplevels;
for my $w (@tl_wins) {
    say "name:  ", $w->get_name;
    say "title: ", $w->get_title;
}

Gtk2->main;

The methods set_name and get_name are inherited from the class Gtk::Widget, further up in the hierarchy. It is common in such a complex hierarchy to find needed functionality in parent classes.

This prints their names and titles, as a demo. There are other identifiers and properties, depending on what you need this for.

Note, since these are bindings for the C libraries the docs are sometimes scattered and incomplete. Searching around for extra documentation is probably a good idea.


The purpose of this, as explained in comments

...from a frame's [button's] signal_connect("clicked"), i open a toplevel window containing a TextView and ScrolledWindow and successfully display data. But if I click on that same frame, it opens another duplicate toplevel instance. I rather either bring to focus the open one, or delete the original and open a new toplevel - basically only ever have 1 instance.

Here is one way for that

use warnings;
use strict;
use feature qw(say state);
 
use Gtk2 -init;

my $window = Gtk2::Window->new('toplevel');
$window->set_default_size(400, 200);
$window->set_position('center');
$window->set_title('Main Window');
$window->signal_connect('delete-event' => sub { Gtk2->main_quit });
$window->show_all;

my $w2 = Gtk2::Window->new('toplevel');
$w2->set_default_size(300, 300);
$w2->set_title('== side ==');
my $bt2 = Gtk2::Button->new('Bring up window');

$bt2->signal_connect(clicked => sub { 
    state $subwin;
    if (not $subwin) { 
        $subwin = Gtk2::Window->new('toplevel');
        $subwin->set_default_size(200, 200);
        $subwin->set_position('center-on-parent');
        my $bt = Gtk2::Button->new('say "hi"');
        $bt->signal_connect(clicked => sub { say "hi" });
        $subwin->add($bt);
        $subwin->show_all;
    }
    else { $subwin->present }
});
$w2->add($bt2);
$w2->show_all;

Gtk2->main;

(I removed some unneeded pieces from the initial example)

To test, once the "side" window is clicked and a new window is created, move it and hide it behind another window. Clicking again re-presents the window.


Corrections for the code in the "FOLLOW-UP QUSTION", which has been added to the question:

  • That callback is written with a prototype, requiring no arguments for the subroutine (the empty () after the sub's name). I take it that prototypes aren't needed here and that () is there in error, but it does mess up passed arguments -- so remove those ().

  • Further down in the sub, the TextBuffer is given the $hostname, presumably intended for the window title, and not data that seems to be intended for scrolled text, seemingly $DS

Then I add that callback to the say "hi" button, calling it after hi is printed. (I need to remove $button from the argument list if it's used this way since it's then not really a callback and the button object doesn't get passed to it.) I make up some data for it and it all works.