#!/usr/bin/perl -w use strict; use Gtk2 -init; use Glib qw(:constants); { # main window my $window = Gtk2::Window->new; $window->signal_connect (destroy => sub {Gtk2->main_quit}); $window->set_default_size (400, 300); my $vbox = Gtk2::VBox->new; my $hbox = Gtk2::HBox->new; my $scroller = Gtk2::ScrolledWindow->new; my $textview = Gtk2::TextView->new; my $toggle = Gtk2::ToggleButton->new ('Poppy'); $window->add ($vbox); $vbox->add ($scroller); $scroller->add ($textview); $vbox->pack_start ($hbox, FALSE, FALSE, 0); $hbox->pack_end ($toggle, FALSE, FALSE, 0); # Toggle the visibility of the "popup" whenever $toggle is toggled. $toggle->signal_connect (toggled => \&toggle_popup); # We need to keep a reference to this so we can use it as the relative # base for the popup's location. $window->{popup_toggle} = $toggle; # Since we're managing the popup ourselves, we'll have to relocate # it whenever the main window's size changes. We don't have to # worry about tracking movement of the main window, because we're # going to make the "popup" be a child widget, rather than a proper # popup window. $window->signal_connect (size_allocate => \&allocate_main_window); $window->show_all; Gtk2->main; } sub toggle_popup { my $toggle = shift; my $window = $toggle->get_toplevel; my $popup = $window->{popup}; if (!$popup) { # Create a little frame with some interesting stuff # inside, and place it in an event box that will # serve as the popup. $popup = Gtk2::EventBox->new; my $frame = Gtk2::Frame->new ("Cool shit"); my $vbox = Gtk2::VBox->new; my $thing1 = Gtk2::CheckButton->new ("thing 1"); my $thing2 = Gtk2::CheckButton->new ("thing 2"); $vbox->add ($thing1); $vbox->add ($thing2); $frame->add ($vbox); $popup->add ($frame); $frame->show_all; # Tell the frame that it belongs to the window. # We'll manage its position in update_popup_position. $popup->set_parent ($window); $window->{popup} = $popup; # for later. } if ($toggle->get_active) { update_popup_position ($window); $popup->show; } else { $popup->hide; } } sub update_popup_position { my ($window) = @_; my $popup = $window->{popup}; return unless $popup; # Keep the popup's lower-right corner pinned to the upper-right # corner of the popup toggle. We're acting as though we are # the popup's container, so use size_allocate() to tell the # widget where to live. Note that we do this regardless of # whether the widget is visible. my $toggle_allocation = $window->{popup_toggle}->allocation; my $popup_width = $popup->size_request->width; my $popup_height = $popup->size_request->height; my $allocation = Gtk2::Gdk::Rectangle->new ( $toggle_allocation->x + $toggle_allocation->width - $popup_width, $toggle_allocation->y - $popup_height, $popup_width, $popup_height); $popup->size_allocate ($allocation); } sub allocate_main_window { my ($window) = @_; # The size of the main window has changed; position the # popup accordingly. update_popup_position ($window); return FALSE; }