[Date Prev][Date Next] [Thread Prev][Thread Next]
[Thread Index]
[Date Index]
[Author Index]
Re: Writing a Perl GNOME Panel Applet
- From: Ed Halley <ed halley cc>
- To: Tom Cross <tomc cloudnet com>
- Cc: Gtk Perl List <gtk-perl-list gnome org>
- Subject: Re: Writing a Perl GNOME Panel Applet
- Date: 29 Jun 2002 21:40:59 -0400
On Sat, 2002-06-29 at 19:26, Tom Cross wrote:
> I'm trying to make a little panel applet using Ximian's Gtk-Perl
> package. However I'm not sure if it includes support for Panel Applet's
> or not. I can't get it to initialize. I've tried:
Here's a small but nontrivial example that I have *mostly* working.
The code should be clean enough you can ignore the parts you don't want
and make your own stuff. Note it needs some icon files in the
appropriate place. Read the code to set that up.
The only serious flaw here may be my fault or may not-- it won't reload
properly when I log out and then log back in.
What I would really like is for someone to help me make the panel applet
draw using the full alpha capability of pixbuf, instead of the crappy
thresholded pixmap methods. I've tried reading through Red Hat's pygtk
rhn_applet code, but they've over-complicated it for fading animations.
--
[ e d @ h a l l e y . c c ]
#!/usr/bin/perl -w
use Gnome;
use Gnome::Applet;
require Gtk::Gdk::Pixbuf;
my $applet = undef;
my $timer = undef;
my $icon = undef;
my %images = ();
my %icons = ();
my %masks = ();
my %pixbuf = ();
my %pixes = ();
my $alarm = 0;
my $vis = 'blue';
exit(main());
#----------------------------------------------------------------------------
sub main
{
my $applet_name = "innaminute_applet";
Gnome::AppletWidget->init($applet_name);
Gtk::Gdk::ImlibImage->init();
Gtk::Gdk::Pixbuf->init();
$applet = new Gnome::AppletWidget($applet_name);
setupImages();
setupWidgets();
Gnome::AppletWidget->gtk_main();
return 0;
}
#----------------------------------------------------------------------------
# Loads all of the original images, for state icons and their masks.
# We request a small initial render size, which will get overridden whenever
# we learn the actual size required.
#
sub setupImages
{
my $path = "/home/speare/bin/";
foreach (qw(blue gray green yellow red))
{
my $filename = "hexagon.$_.104.png";
my $image = Gtk::Gdk::ImlibImage->load_image($path . $filename);
warn "Could not load image $filename" if not $image;
$images{$_} = $image;
}
renderIcons(2);
}
# Whenever the widget changes size, this function re-renders the required
# scaled icons and masks for each available state.
#
sub renderIcons
{
my $size = shift;
foreach (keys %images)
{
$images{$_}->render($size, $size);
# free existing icon and mask if they exist
$icons{$_} = $images{$_}->copy_image();
$masks{$_} = $images{$_}->copy_mask();
}
}
# Whenever desired, the widget's current icon and mask can be chosen by
# the predefined state keywords, such as 'red' or 'disabled'.
#
sub switchIcon
{
my ($icon, $state) = @_;
return if not defined $icons{$state} or not defined $masks{$state};
$icon->set($icons{$state}, $masks{$state});
}
#----------------------------------------------------------------------------
# Assembles the applet's widgets. Also sets up the responses for all of
# the signals received by these widgets.
#
sub setupWidgets
{
my $idletip = "InnaMinute";
$applet->set_tooltip($idletip);
# Set up the registered applet menu items.
# The canned choices are simple future alarms, such as
# "remind me in a minute", which is where the applet gets its name.
#
my @choices =
(
[ "minute", "Remind me in a minute", sub { setAlarm(time() + 1*60); } ],
[ "5minute", "Remind me in 5 minutes", sub { setAlarm(time() + 5*60); } ],
[ "10minute", "Remind me in 10 minutes", sub { setAlarm(time() + 10*60); } ],
[ "15minute", "Remind me in 15 minutes", sub { setAlarm(time() + 15*60); } ],
[ "30minute", "Remind me in half an hour", sub { setAlarm(time() + 30*60); } ],
[ "45minute", "Remind me in 45 minutes", sub { setAlarm(time() + 45*60); } ],
[ "60minute", "Remind me in one hour", sub { setAlarm(time() + 1*60*60); } ],
[ "reset", "Cancel pending reminder", sub { resetAlarm(); } ],
);
foreach (@choices)
{
$applet->register_callback($_->[0], $_->[1], $_->[2]);
}
if (0)
{
$applet->register_callback("du de dum", "hop hop", sub
{
print "yeppa\n";
} );
$applet->register_callback_dir("test", "dir");
$applet->register_stock_callback("test/du de dam", "About", "hip hip", sub
{
print "yeppa 2\n";
} );
}
# Create a mouse-sensitive widget which displays an icon.
# The icon to be displayed may be adjusted based on applet status.
$icon = new Gtk::Pixmap($icons{blue}, $masks{blue});
my $ev = [ 'button_press_mask' ];
my $oev = $applet->get_events();
push(@{$ev}, $oev) if scalar keys %{$oev};
$applet->set_events($ev);
$applet->signal_connect('button_press_event',
sub
{
onAppletPress($applet);
return 1;
} );
$icon->show();
$applet->add($icon);
# Respond to generic panel size changes. We collect all these bits
# of information in one map, and respond to them all in the same way.
my $panel = { };
$applet->signal_connect("change_orient", sub
{ my $widget = shift;
$panel->{orient} = shift;
onPanelResize($icon, $panel);
} );
$applet->signal_connect("back_change", sub
{ my $widget = shift;
$panel->{backtype} = shift;
$panel->{backpixmap} = shift;
$panel->{backcolor} = shift;
onPanelResize($icon, $panel);
} );
$applet->signal_connect("change_pixel_size", sub
{ my $widget = shift;
$panel->{panelsize} = shift;
onPanelResize($icon, $panel);
} );
# Finally.
$applet->show();
}
#----------------------------------------------------------------------------
# When the panel size is first discovered or subsequently resized, we
# decide the appropriate layout and any graphic scaling necessary.
#
# In this case, it's a simple square that matches the panel's size.
#
sub onPanelResize
{
my ($icon, $panel) = (@_);
my $size = $panel->{panelsize};
renderIcons($size) if defined $size;
onTimer();
}
# When the user clicks on the applet area, we decide the appropriate
# action. This could be to pop up a menu or a toplevel window for further
# choices, or to merely toggle through a simple state.
#
# In this case, it's a pop-up menu.
#
sub onAppletPress
{
print "onAppletPress\n";
my ($applet) = @_;
}
#----------------------------------------------------------------------------
# Updates the icon to the appropriate state depending on pending schedule.
# Used as the Gtk timeout callback, but can be called in other situations.
#
sub onTimer
{
if (not defined $timer)
{
switchIcon($icon, 'blue');
return 1;
}
# If the time has elapsed, pop up the reminder. The alarm and timer
# isn't actually fully reset until the reminder is cleared, so our
# applet icon will still flash.
#
my $now = time();
if ($alarm > 0 && $alarm <= $now)
{
$alarm = 0;
onAlarm();
}
# Decide the color depending on how much time remains on the timer.
#
if ($vis eq 'green')
{ $vis = 'yellow'; }
elsif ($vis eq 'yellow')
{ $vis = 'red'; }
else
{ $vis = 'green'; }
switchIcon($icon, $vis);
return 1;
}
# Set up an alarm at a specified perl-time. Overrides any existing alarm.
# Setting an alarm for time zero is the same as resetAlarm.
# Setting an alarm in the past will immediately trigger.
#
sub setAlarm
{
my $when = shift;
if ($when <= 0)
{
resetAlarm();
return;
}
$alarm = $when;
print "Alarm set for ", $when - time(), " seconds in the future.\n";
$timer = Gtk->timeout_add(250, \&onTimer) if not defined $timer;
onTimer();
}
# Remove any pending alarm.
#
sub resetAlarm
{
$alarm = 0;
switchIcon($icon, 'blue');
if (defined $timer)
{
Gtk->timeout_remove($timer);
$timer = undef;
}
}
# Display a simple modal box to remind the user that their alarm has rung.
# TODO: ask window manager to make this reminder 'sticky' if possible.
#
sub onAlarm
{
my $window = new Gtk::Window("toplevel");
$window->set_title("InnaMinute");
$window->signal_connect("delete_event",
sub { onKillReminder($window); } );
$window->border_width(10);
$window->set_modal(1);
my $message = "Reminder! Reminder!";
my $button = new Gtk::Button($message);
$button->signal_connect("clicked",
sub { onKillReminder($window); } );
$button->can_default(1);
$button->show();
$window->add($button);
$window->set_default($button);
$window->show();
}
# Terminate the reminder window, the animations timer,
# and get everything back to normal.
#
sub onKillReminder
{
my $window = shift;
$window->destroy();
resetAlarm();
}
#----------------------------------------------------------------------------
# Gtk::Perl Tips and Tricks
sub getWindowScreenPosition
{
my $window = shift;
my ($x, $y, $w, $h) = @{$window->allocation};
($x, $y) = $window->window->get_root_origin();
return ($x, $y, $w, $h);
}
sub setWindowScreenPosition
{
my ($window, $x, $y, $w, $h) = @_;
$window->set_default_size($w, $h);
$window->set_uposition($x, $y);
}
[Date Prev][Date Next] [Thread Prev][Thread Next]
[Thread Index]
[Date Index]
[Author Index]