Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

Gtk2 Interactive Chat client

by zentara (Archbishop)
on Jan 21, 2008 at 20:50 UTC ( [id://663428]=CUFP: print w/replies, xml ) Need Help??

Here is a basic Gtk2 based interactive chat client. It could be a bit simpler, if you didn't care about warning messages concerning various errors such as: printing to a closed socket, reconnecting after a disconnect, etc. So there are some comments describing the minimal error checking to avoid scary messages/warnings. Also some extra color adding code. There is a server at Simple threaded chat server to test this client with. It is basically a Gtk2 version of the Tk client in the above node.

As always, thanks to muppet(Perl/Gtk2 maillist guru) for some boiler-plate code for watching a filehandle.

#!/usr/bin/perl use warnings; use strict; use Glib qw(TRUE FALSE); use Gtk2 -init; use IO::Socket; my $name = shift || 'anon'; my $host = 'localhost'; my $port = 12345; my $socket; # make entry widget larger, colored text Gtk2::Rc->parse_string(<<__); style "my_entry" { font_name ="arial 30" text[NORMAL] = "#FF0000" } style "my_text" { font_name ="sans 12" text[NORMAL] = "#FFAA00" base[NORMAL] = "#000000" GtkTextView::cursor-color = "red" } style "my_cursor"{ fg[NORMAL] = "#FF0000" } widget "*Text*" style "my_text" widget "*Entry*" style "my_entry" __ my $window = Gtk2::Window->new; $window->signal_connect( delete_event => sub { exit } ); $window->set_default_size( 400, 300 ); my $vbox = Gtk2::VBox->new; $window->add($vbox); my $scroller = Gtk2::ScrolledWindow->new; $vbox->add($scroller); my $textview = Gtk2::TextView->new; $textview ->set_editable (0); #read-only text $textview ->can_focus(0); # my $buffer = $textview->get_buffer; $buffer->create_mark( 'end', $buffer->get_end_iter, FALSE ); $buffer->signal_connect( insert_text => sub { $textview->scroll_to_mark( $buffer->get_mark('end'), 0.0, TRUE +, 0, 0.5 ); } ); $scroller->add($textview); my $entry = Gtk2::Entry->new(); $vbox->pack_start( $entry, FALSE, FALSE, 0 ); $vbox->set_focus_child ($entry); # keeps cursor in entry $window->set_focus_child ($entry); # keeps cursor in entry # allows for sending each line with an enter keypress my $send_sig = $entry->signal_connect ('key-press-event' => sub { my ($widget,$event)= @_; if( $event->keyval() == 65293){ # a return key press my $text = $entry->get_text; if(defined $socket){ print $socket $name.'->'. $text, "\n";} $entry->set_text(''); $entry->set_position(0); } }); #If you store the ID returned by signal_connect, you can temporarily #block your signal handler with # $object->signal_handler_block ($handler_id) # and unblock it again when you're done with ## $object->signal_handler_unblock ($handler_id). # we want to block/unblock the enter keypress depending # on the state of the socket $entry->signal_handler_block($send_sig); #not connected yet $entry->set_editable(0); my $button = Gtk2::Button->new('Connect'); $button->signal_connect( clicked => \&init_connect ); $vbox->pack_start( $button, FALSE, FALSE, 0 ); $window->show_all; Gtk2->main; exit; sub init_connect{ $socket = IO::Socket::INET->new( PeerAddr => $host, PeerPort => $port, Proto => 'tcp', ); if( ! defined $socket){ my $buffer = $textview->get_buffer; $buffer->insert( $buffer->get_end_iter, "ERROR: Can't connect to port $port on $host: $!\n" ); return; } #if we have a socket $button->set_label('Connected'); $button->set_state('insensitive'); # install an io watch for this stream and # return immediately to the main caller, who will return # immediately to the event loop. the callback will be # invoked whenever something interesting happens. Glib::IO->add_watch( fileno $socket, [qw/in hup err/], \&watch +_callback, $socket ); #turn on entry widget $entry->set_editable(1); $entry->grab_focus; $entry->signal_handler_unblock ($send_sig); Gtk2->main_iteration while Gtk2->events_pending; } sub watch_callback { my ( $fd, $condition, $fh ) = @_; if ( $condition >= 'in' ) { # there's data available for reading. we have no my $bytes = sysread( $fh, my $data, 1024); if ( defined $data ) { # do something useful with the text. my $buffer = $textview->get_buffer; $buffer->insert( $buffer->get_end_iter, $data ); } } if ( $condition >= 'hup' or $condition >= 'err' ) { # End Of File, Hang UP, or ERRor. that means # we're finished. # stop ability to send $entry->set_editable(0); $entry->signal_handler_block ($send_sig); my $buffer = $textview->get_buffer; $buffer->insert( $buffer->get_end_iter, "Server connection los +t !!\n" ); #close socket $fh->close; $fh = undef; #allow for new connection $button->set_label('Connect'); $button->set_sensitive(1); $button->grab_focus; Gtk2->main_iteration while Gtk2->events_pending; } if ($fh) { # the file handle is still open, so return TRUE to # stay installed and be called again. # print "still connected\n"; # possibly have a "connection alive" indicator return TRUE; } else { # we're finished with this job. start another one, # if there are any, and uninstall ourselves. return FALSE; } } __END__

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: CUFP [id://663428]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others sharing their wisdom with the Monastery: (5)
As of 2024-04-19 12:08 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found