Category: | GUI Programming |
Author/Contact Info | zentara of perlmonks |
Description: | I recently posted Gtk2 TrayIcon Demo, but it turns out that TrayIcon dosn't work on Win32, and is being phased out in favor of StatusIcon. So here basically is the same code, but using StatusIcon (which will accept most any image and auto-magically make an icon for you). This code is mostly used to demonstrate how to setup a nice right-click configuration window. The left click just tails the script itself.....you can make it do whatever you want. |
#!/usr/bin/perl use warnings; use strict; use Gtk2 '-init'; use MIME::Base64; my %icon; build_icons(); # r,g,y my $icon_cur = $icon{ 'g' }; my %val; while(<DATA>){ chomp; my($key,$value) = split(/=/,$_); if( defined $key){ $val{$key} = $value; } } # check data reloaded properly #foreach my $key(sort keys %val){print $key.'='.$val{$key}."\n"} # default global variables if not saved to __DATA__ $val{'dir'} ||= './'; $val{'file'} ||= $0; $val{'check1'} ||= 1; $val{'check2'} ||= 0; $val{'check3'} ||= 0; $val{'var1'} ||= 'VAR1'; $val{'var2'} ||= 'VAR2'; $val{'var3'} ||= 'VAR3'; $val{'var4'} ||= 'VAR4'; $val{'var5'} ||= 'VAR5'; $val{'var6'} ||= 'VAR6'; $val{'var7'} ||= 'VAR7'; $val{'var8'} ||= 'VAR8'; $val{'var9'} ||= 'VAR9'; $val{'var10'} ||= 'VAR10'; my $statusicon = Gtk2::StatusIcon->new_from_pixbuf($icon_cur); # will make a nice icon automagically from a file if desired #my $statusicon = Gtk2::StatusIcon->new_from_file('12uni2.png'); $statusicon->set_tooltip("Info v1.0"); $statusicon->signal_connect( 'activate', \&pop_it ); $statusicon->signal_connect( 'popup-menu', \&config_it ); #show in tray $statusicon->set_visible(1); #end event loop Gtk2->main; sub pop_it{ my $popup = Gtk2::Window->new( 'toplevel' ); $popup->set_position( 'center' ); my $vbox = Gtk2::VBox->new( 0, 6 ); $popup->add($vbox); $vbox->set_border_width(2); my $hbox= Gtk2::HBox->new( 0, 6 ); $vbox->pack_end($hbox,0,0,2); my $ebutton = Gtk2::Button->new_from_stock('gtk-close'); $hbox->pack_end( $ebutton, 0, 0, 0 ); $ebutton->signal_connect( clicked => sub{ $popup->hide_all } ); # Create a textbuffer to contain that string my $textbuffer = Gtk2::TextBuffer->new(); my $tail = `tail -n 20 $val{'file'}`; $textbuffer->set_text($tail); # Create a textview using that textbuffer my $textview = Gtk2::TextView->new_with_buffer($textbuffer); # Add the textview to a scrolledwindow my $scrolledwindow = Gtk2::ScrolledWindow->new( undef, undef ); $scrolledwindow->add($textview); $scrolledwindow->set_size_request (300, 300); $vbox->pack_start($scrolledwindow, 1, 1, 0 ); $popup->show_all; } #right click menu sub config_it { # change Mode or whatever.... a menu entry my $menu = Gtk2::Menu->new(); my $menu_Z1 = Gtk2::ImageMenuItem->new_with_label( "Mode Z1" ); $menu_Z1->signal_connect( activate => sub { #change the icon when Z1 is clicked in the menu $statusicon->set_from_pixbuf($icon{'y'}); $statusicon->set_tooltip( "Mode Z1" ); } ); $menu_Z1->set_image( Gtk2::Image->new_from_stock( 'gtk-refresh', 'm +enu' ) ); $menu->add( $menu_Z1); # launch configure window my $menu_pref = Gtk2::ImageMenuItem->new_with_label( "Configure" ); $menu_pref->signal_connect( activate => \&configure ); $menu_pref->set_image( Gtk2::Image->new_from_stock( 'gtk-preferences', 'menu' ) ); $menu->add( $menu_pref ); #separator my $menu_sep = Gtk2::SeparatorMenuItem->new(); $menu->add( $menu_sep ); #Quit my $menu_quit = Gtk2::ImageMenuItem->new_with_label( "Quit" ); $menu_quit->signal_connect( activate => \&exit_it ); $menu_quit->set_image( Gtk2::Image->new_from_stock( 'gtk-quit', 'me +nu' ) ); $menu->add( $menu_quit ); $menu->show_all; #to position the menu under the icon, instead of at mouse position my ($x, $y, $push_in) = Gtk2::StatusIcon::position_menu($menu, $statu +sicon); # print "$x, $y, $push_in\n"; $menu->popup( undef, undef, sub{return ($x,$y,0)} , undef, 0, 0 ); return 1; } #configuration dialog window sub configure { #Create the new window my $config_window = Gtk2::Window->new( 'toplevel' ); $config_window->set_title( "Configuration" ); $config_window->set_position( 'center' ); #VBox container my $table_config = Gtk2::Table->new( 3, 5, 0 ); #Create Notebook my $config_notebook = Gtk2::Notebook->new; $config_notebook->set_tab_pos( 'top' ); #the First Page; Config file select my $vbox_p1 = Gtk2::VBox->new( 0, 1 ); my $hbox_1_p1 = Gtk2::HBox->new( 0, 1 ); my $label_1_p1 = Gtk2::Label->new( 'Directory' ); my $entry_1_p1 = Gtk2::Entry->new; $entry_1_p1->set_width_chars (60); $entry_1_p1->set_position(60); my $button_1_p1 = Gtk2::Button->new_with_mnemonic( "_Browse" ); $button_1_p1->set_size_request( 80, 32 ); my $align_button_1_p1 = Gtk2::Alignment->new( 0.5, 0.5, 0, 0 ); $align_button_1_p1->add( $button_1_p1 ); $entry_1_p1->set_text( $val{'dir'} ); $hbox_1_p1->pack_start( $label_1_p1, 0, 0, 1 ); $hbox_1_p1->pack_start( $entry_1_p1, 1, 1, 1 ); $hbox_1_p1->pack_start( $align_button_1_p1, 0, 0, 1 ); my $hbox_2_p1 = Gtk2::HBox->new( 0, 1 ); my $label_2_p1 = Gtk2::Label->new( 'Tail File' ); my $entry_2_p1 = Gtk2::Entry->new; $entry_2_p1->set_width_chars (60); $entry_2_p1->set_position(60); my $button_2_p1 = Gtk2::Button->new_with_mnemonic( "_Browse" ); $button_2_p1->set_size_request( 80, 32 ); my $align_button_2_p1 = Gtk2::Alignment->new( 0.5, 0.5, 0, 0 ); $align_button_2_p1->add( $button_2_p1 ); $entry_2_p1->set_text( $val{'file'} ); $hbox_2_p1->pack_start( $label_2_p1, 0, 0, 1 ); $hbox_2_p1->pack_start( $entry_2_p1, 1, 1, 1 ); $hbox_2_p1->pack_start( $align_button_2_p1, 0, 0, 1 ); $vbox_p1->pack_start( $hbox_1_p1, 0, 0, 1 ); $vbox_p1->pack_start( $hbox_2_p1, 0, 0, 1 ); $button_1_p1->signal_connect( 'clicked' => sub { my $fs = Gtk2::FileChooserDialog->new( 'Choose a Directory', $config_window, 'select-folder', 'gtk-cancel' => 'cancel', 'gtk-ok' => 'accept' ); my $response = $fs->run(); if ( "accept" eq $response ) { my $dir = $fs->get_filename(); $entry_1_p1->set_text( $dir ); } $fs->destroy; } ); $button_2_p1->signal_connect( 'clicked' => sub { my $fs = Gtk2::FileChooserDialog->new( "FS", $config_window, 'open', "Cancel" => "cancel", "OK" => "accept", ); my $response = $fs->run(); if ( "accept" eq $response ) { my $file = $fs->get_filename(); $entry_2_p1->set_text( $file ); } $fs->destroy; } ); my $checkbutton1 = Gtk2::CheckButton->new('Some Feature1'); $checkbutton1->set_active( $val{'check1'} ); $vbox_p1->pack_start( $checkbutton1, 0, 0, 1 ); $checkbutton1->signal_connect( clicked => \&check_button_callback1 ); my $checkbutton2 = Gtk2::CheckButton->new_with_label('Flashing Warning +'); $checkbutton2->set_active( $val{'check2'} ); $vbox_p1->pack_start( $checkbutton2, 0, 0, 1 ); $checkbutton2->signal_connect( clicked => \&check_button_callback2 ); my $checkbutton3 = Gtk2::CheckButton->new_with_mnemonic('Red Icon'); $checkbutton3->set_active( $val{'check3'} ); $vbox_p1->pack_start( $checkbutton3, 0, 0, 1 ); $checkbutton3->signal_connect( clicked => \&check_button_callback3 ); #the Second Page; my $vbox_p2 = Gtk2::VBox->new( 0, 1 ); my $label_1_p2 = Gtk2::Label->new( 'Label 1' ); my $entry_1_p2 = Gtk2::Entry->new; my $label_2_p2 = Gtk2::Label->new( 'Label2' ); my $entry_2_p2 = Gtk2::Entry->new; $entry_1_p2->set_text( $val{'var1'} ); $entry_2_p2->set_text( $val{'var2'} ); $vbox_p2->pack_start( $label_1_p2, 0, 0, 1 ); $vbox_p2->pack_start( $entry_1_p2, 0, 0, 1 ); $vbox_p2->pack_start( $label_2_p2, 0, 0, 1 ); $vbox_p2->pack_start( $entry_2_p2, 0, 0, 1 ); #the Third Page; my $table_p3 = Gtk2::Table->new( 4, 2, 0 ); my $label_1_p3 = Gtk2::Label->new( 'First Label' ); my $entry_1_p3 = Gtk2::Entry->new; my $label_2_p3 = Gtk2::Label->new( 'Second label' ); my $entry_2_p3 = Gtk2::Entry->new; my $label_3_p3 = Gtk2::Label->new( 'Third Label' ); my $entry_3_p3 = Gtk2::Entry->new; my $label_4_p3 = Gtk2::Label->new( 'Fourth Label' ); my $entry_4_p3 = Gtk2::Entry->new; $entry_1_p3->set_text( $val{'var3'} ); $entry_2_p3->set_text( $val{'var4'} ); $entry_3_p3->set_text( $val{'var5'} ); $entry_4_p3->set_text( $val{'var6'} ); # $entry_3_p3->set_editable( 0 ); # if no edit desired $table_p3->attach_defaults( $label_1_p3, 0, 1, 0, 1 ); $table_p3->attach_defaults( $entry_1_p3, 1, 2, 0, 1 ); $table_p3->attach_defaults( $label_2_p3, 0, 1, 1, 2 ); $table_p3->attach_defaults( $entry_2_p3, 1, 2, 1, 2 ); $table_p3->attach_defaults( $label_3_p3, 0, 1, 2, 3 ); $table_p3->attach_defaults( $entry_3_p3, 1, 2, 2, 3 ); $table_p3->attach_defaults( $label_4_p3, 0, 1, 3, 4 ); $table_p3->attach_defaults( $entry_4_p3, 1, 2, 3, 4 ); #the Fourth Page; my $vbox_p4 = Gtk2::VBox->new( 0, 1 ); my $table_1_p4 = Gtk2::Table->new( 4, 2, 0 ); my $frame_1_p4 = Gtk2::Frame->new( 'Some Cool Title' ); my $label_1_p4 = Gtk2::Label->new( 'First Label' ); my $entry_1_p4 = Gtk2::Entry->new; my $label_2_p4 = Gtk2::Label->new( 'Second Label' ); my $entry_2_p4 = Gtk2::Entry->new; $entry_1_p4->set_text( $val{'var7'} ); $entry_2_p4->set_text( $val{'var8'} ); $table_1_p4->attach_defaults( $label_1_p4, 0, 1, 0, 1 ); $table_1_p4->attach_defaults( $entry_1_p4, 1, 2, 0, 1 ); $table_1_p4->attach_defaults( $label_2_p4, 0, 1, 1, 2 ); $table_1_p4->attach_defaults( $entry_2_p4, 1, 2, 1, 2 ); $frame_1_p4->add( $table_1_p4 ); my $table_2_p4 = Gtk2::Table->new( 4, 2, 0 ); my $frame_2_p4 = Gtk2::Frame->new( 'Another Cool Title' ); my $label_3_p4 = Gtk2::Label->new( 'Third Label' ); my $entry_3_p4 = Gtk2::Entry->new; my $label_4_p4 = Gtk2::Label->new( 'Fourth Label' ); my $entry_4_p4 = Gtk2::Entry->new; $entry_3_p4->set_text( $val{'var9'} ); $entry_4_p4->set_text( $val{'var10'}); $table_2_p4->attach_defaults( $label_3_p4, 0, 1, 0, 1 ); $table_2_p4->attach_defaults( $entry_3_p4, 1, 2, 0, 1 ); $table_2_p4->attach_defaults( $label_4_p4, 0, 1, 1, 2 ); $table_2_p4->attach_defaults( $entry_4_p4, 1, 2, 1, 2 ); $frame_2_p4->add( $table_2_p4 ); $vbox_p4->pack_start( $frame_1_p4, 0, 0, 1 ); $vbox_p4->pack_start( $frame_2_p4, 0, 0, 1 ); #append pages $config_notebook->append_page( $vbox_p1, "File Stuff" ); $config_notebook->append_page( $vbox_p2, "More Items" ); $config_notebook->append_page( $table_p3, "More in a Table" ); $config_notebook->append_page( $vbox_p4, "Another Table Set" ); #add button to the main window my $button_accept = Gtk2::Button->new_with_mnemonic( "_Accept" ); my $button_cancel = Gtk2::Button->new_with_mnemonic( "_Cancel" ); #pack them into the dialog window $table_config->attach_defaults( $config_notebook, 0, 5, 0, 1 ); $table_config->attach_defaults( $button_accept, 1, 2, 2, 3 ); $table_config->attach_defaults( $button_cancel, 3, 4, 2, 3 ); $config_window->add( $table_config ); $config_window->show_all; #Button Functions $button_cancel->signal_connect( 'clicked' => sub { $config_window-> +destroy } ); $button_accept->signal_connect( 'clicked' => sub { my @settings = ( ( $val{'dir'} = $entry_1_p1->get_text ), ( $val{'file'} = $entry_2_p1->get_text ), ( $val{'check1'} = $checkbutton1->get_active() || 0 ), ( $val{'check2'} = $checkbutton2->get_active() || 0 ), ( $val{'check3'} = $checkbutton3->get_active() || 0 ), ( $val{'var1'} = $entry_1_p2->get_text ), ( $val{'var2'} = $entry_2_p2->get_text ), ( $val{'var3'} = $entry_1_p3->get_text ), ( $val{'var4'} = $entry_2_p3->get_text ), ( $val{'var5'} = $entry_3_p3->get_text ), ( $val{'var6'} = $entry_4_p3->get_text ), ( $val{'var7'} = $entry_1_p4->get_text ), ( $val{'var8'} = $entry_2_p4->get_text ), ( $val{'var9'} = $entry_3_p4->get_text ), ( $val{'var10'} = $entry_4_p4->get_text ), ); save_default(); $config_window->destroy; } ); return 1; } #Exit sub exit_it { Gtk2->main_quit; return 0; } #save to DATA when apply is clicked sub save_default { open(SELF,"+<$0")||die $!; while(<SELF>){last if /^__DATA__/} truncate(SELF,tell SELF); foreach my $key(sort keys %val ) { print SELF $key.'='.$val{$key}."\n"; #default line ending } truncate(SELF,tell SELF); close SELF; } sub check_button_callback1 { my ($button) = @_; if ($button->get_active) { # if control reaches here, the check button is on # do something here } else { # if control reaches here, the check button is off # undo something here } } sub check_button_callback2 { my ($button) = @_; if ($button->get_active) { # if control reaches here, the check button is on $statusicon->set_from_pixbuf($icon{'y'}); $statusicon->set_tooltip( "Mode Yellow Warning" ); $statusicon->set_blinking (1); } else { # if control reaches here, the check button is off $statusicon->set_from_pixbuf($icon_cur); $statusicon->set_tooltip( "Mode Normal" ); $statusicon->set_blinking (0); } } sub check_button_callback3 { my ($button) = @_; if ($button->get_active) { # if control reaches here, the check button is on $statusicon->set_from_pixbuf($icon{'r'}); $statusicon->set_tooltip( "Mode Red" ); } else { # if control reaches here, the check button is off $statusicon->set_from_pixbuf($icon_cur); $statusicon->set_tooltip( "Mode Normal" ); } } sub build_icons { my %data; $data{ 'r' } = decode_base64( 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+ +gvaeTAAAACXBI WXMAAAsTAAALEwEAmpwYAAAB00lEQVRYw+3WP2gUURAG8N++iwoRxRSilSiiHN4iWJhe7M +TCQiJW IqiFtUIQQWyENNpZxkYxjVgKNnb24hUGQe0s0gj+PcztWtw7WC63d2TJbQrvwbK8x2Pmm2 +++mXlJ nue2cwXbvKYApgBmqsFON55l7f8rBQv4gm/xv1AVQLLpRtSjfx2NwmkXM1XSUJWBxpj9tA +wnDuDj mP2E+wDH+yKun4Ge0pPCB3ndjegXslh+GfK6NfBjYF8jgJDux+7trIIz2DXYUesB0It+ea +jDkC7X wcBpzJbk/KKQvhbSxiQBPB8hug5O4s5kAIT0K/ZE54NRZtiLOdwU0qtbByCkTSH9hANDor ++BD9FO wM4IYinqZUsYeIHDBbX3o7+NFVwvtPXv8c4+fBbSZrUHSQ/9I5yLxgZVfx6vYjkmuILHQ5 +pTNw6q a7L223IAPYfHcBZHo+MyCluR9h2R8k68O4unmB82QbCKl3iHN3GurCV50rqEyziCZjQ6bD +2JrKwi kbU7Bcbm8BMHcRcXSgLo072O93iQ5ElrXB/v4iEWo+PuiLdiP1UnYsOaH2P7zygAv7Eka9 ++vMC8S HMJf3IvVUiLCjQDWcAvPSqPdPKAGTsXULBYqKf8H7mhziLP34moAAAAASUVORK5CYII=' ); $data{ 'g' } = decode_base64( 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+ +gvaeTAAAACXBI WXMAAAsTAAALEwEAmpwYAAABwUlEQVRYw+2VvS8EURTFf8/4CKJQTKOgEIlEqFCIRnSUhE +6iUOhV Go3Kf0ChkiipNWqFQuErEtFJSEREfO7O0dyNid2Z3X3sbmHfy82bdzPv3TPnnnvHSaKWo4 +EajzqA OoBGn0MOl+cT+l8pmANugEdb53wBuHIbkdGfAYKYOws0+qTBl4GgyL5ehhUHcFVkX3ERfm +9jraAq IrQgLmbewX+TghcgsvKLAFVbA895xFQLgMOFQHstq2ACaMnD5TsklWyIEPGMiFDe3C7nrp +yVy8AI 0JaQ81mHO3C4oJIp2E0R3TswBKxWJAWIW6M+W4D+LOLd7BaxWPq9xQP3I64teITIxAIvIc +7t+dPW N8QdIvwrAKex4PG5guhAjMd8T8bCh4m13wuAqX0H8ZCg+GlEA6IV0YZYLvBOZKycIcaSAD +hJuebS B0wCvcAUECbIZgC4AJqAZhNfaNWxA4wWOBMBl8AecAIc2n/lHsQ8Yh9xYvQlzW3EIKIZ0f +KDsU7z dyO2TANKYCWyFB0jZkgJmJsZxIZRHqRoBYQzG0AclXD3axqAF8SaT3czED2ILsRmKoQCrj +vEQtrX egAKEMOI9R9lHH0BkYPO/OE8jeIAAAAASUVORK5CYII=' ); $data{ 'y' } = decode_base64( 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+ +gvaeTAAAACXBI WXMAAAsTAAALEwEAmpwYAAAB2UlEQVRYw+3WP2gUQRQG8N/mokJEMRyi2UIUUQ4FwcL0Yi +cWFhKx EkEtrBWCCGIjpNHOMjaKNmIp2NjZi41BUKuzSBYE/x7mbi12DpbL7R1ZcnuFN7AsM8y897 +3vvffN RGmaGueYMuYxATABMF3qVBJvXKs3/68ULOALvoX/QlkA0aaFKKN/HbXcahvTZdJQloHakP +mkDUcO 4OOQ+Yh1gKPdIq6egazSo9wHadVC9Aud0H4dpFXXwI+eeYUAkngvdo6zC05jR6+iVgMgi3 +65r8Mk Xq6CgVOYKcj5BUn8WhLXRgng2YCia+EEbo8GQBJ/xa7gvDfKDnZjFjck8ZWtA5DEDUn8Cf +v6RH8d H4KdKWwPIJZCvWwJAy9wMFft3ehv4Tmu5WT9e9izB58lcaPcgyRD/xBng7Heqj+HV6EdI1 +zGoz7i 1A4X1VX15ttiAJnDIziDw8FxEYXHA+3bAuWtsHcGTzDf50wHK3iJd3gT7pXVKF2bu4hLOI +RGMNpv PA6srCBSb7ZyjM3iJ/bjDs4XBNClex3vcT9K1+aG6XgbD7AYHLcHvBW7qToWBGt+iO0/gw +D8xpJ6 816J+yLCAfzF3dAtBUW4EcAqbuJpYbSbB1TDyZCaxVwnpf8AkwJ+jVuvoFMAAAAASUVORK +5CYII=' ); # this properly renders them to pixbuf foreach my $key ( keys %data ) { $icon{ $key } = do { my $loader = Gtk2::Gdk::PixbufLoader->new(); $loader->write( $data{ $key } ); $loader->close(); $loader->get_pixbuf(); }; } } __DATA__ check1=1 check2=0 check3=0 dir=./ file=./zzz-statusicon var1=VAR1 var10=VAR10 var2=VAR2 var3=VAR3 var4=VAR4 var5=VAR5 var6=VAR6 var7=VAR7 var8=VAR8 var9=VAR9 |
Back to
Code Catacombs