Textview not scrolling to show full text in IRC client

Textview not scrolling to show full text in IRC client

am 14.04.2008 22:23:10 von deadpickle

I have this IRC client that wont scroll far enough down to show the
full text. Its rather hard to explain but I'll give it a try:
when you get down to the bottom on the textview and you go to enter a
message such as:
John(10:00:00) I have to go to the story today and get some fruit.

And this message is the last one to be entered before the bottom of
the window therefore causing it to have to scroll down, the program
only shows the first line:
John(10:00:00) I have to go to the story

Forcing the user to scroll down to view the rest:
today and get some fruit.

You can see that this would be a problem when users are chatting,
having to always take your attention off of the session just to scroll
down and view the whole message. Currently the program uses the code
$chat_textview->scroll_to_mark wher mark is the end iter of the
buffer. I cant figure how to get this to work and show the whole text
without the user having to manually scroll down. I figured that this
would do it but it wont work. Here is the code, its functional so you
can try it and see what I mean.

#!/usr/local/bin/perl -w
use strict;
use Gtk2 '-init';
use Glib qw/TRUE FALSE/;
use Net::IRC;
use threads;
use threads::shared;

my $irc = new Net::IRC;
my $chat_state = 'Connect';
my $chat_entry;
my $chat_send_sig;
my $chat_textview;
my $chat_button;
my $sys_msg;
my $tag;
my $job = 1;

my $die:shared = 0;
my $chat_start:shared = 0;
my $channel:shared = "#GRRUVI";
my $irc_server:shared = "irc.servercentral.net";
my $nick:shared = "VCBase";
my $msg:shared;
my $post:shared = 0;
my $name:shared = 0;
my $list:shared;

#################################################
#Threads
my $thread_chat = threads->new(\&chat);

#################################################

#################################################
#Timeout
my $timer_post = Glib::Timeout->add(100, \&post);

#################################################

#-------------------Main Loop-------------------
&chat_build;

Gtk2->main;

####################CHAT BLOCK####################
#-------------------chat Build-------------------
sub chat_build {
my $chat_window = Gtk2::Window->new('toplevel');
$chat_window->set_title('Chat Client');
$chat_window->set_position('center');
$chat_window->set_default_size( 300, 300 );
$chat_window->signal_connect(delete_event=> sub{
$die = 1;
$thread_chat->join;
Gtk2->main_quit;
});

$chat_entry = Gtk2::Entry->new;
my $chat_vbox = Gtk2::VBox->new;

my $chat_scroll = Gtk2::ScrolledWindow->new(undef, undef);
$chat_scroll->set_policy('never', 'always');
$chat_scroll->set_shadow_type( 'etched-out');
$chat_textview = Gtk2::TextView->new;

my $chat_buffer = $chat_textview->get_buffer;
$chat_buffer->create_mark( 'end', $chat_buffer->get_end_iter,
FALSE );
$chat_buffer->signal_connect(insert_text => sub {
$chat_textview->scroll_to_mark( $chat_buffer->get_mark('end'),
0.0, TRUE, 0.0, 1.0 );
});
$chat_button = Gtk2::Button->new;
$chat_button->set_label($chat_state);


# allows for sending each line with an enter keypress
$chat_send_sig = $chat_entry->signal_connect ('key-press-event' =>
sub {
my ($widget,$event)= @_;
if( $event->keyval() == 65293){ # a return key press
$msg = $chat_entry->get_text;
$chat_entry->set_text('');
$chat_entry->set_position(0);
$chat_start = 2;
$name = $nick;
$post = 6;
#print "$chat_start\n";
}
});

$chat_entry->signal_handler_block($chat_send_sig); #not connected
yet
$chat_entry->set_editable(0);
$chat_textview->set_editable(0);
$chat_textview->set_cursor_visible(0);
$chat_textview->set_wrap_mode('char');

$chat_scroll->add($chat_textview);
$chat_vbox->add($chat_scroll);
$chat_vbox->pack_start( $chat_entry, FALSE, FALSE, 0 );
$chat_vbox->pack_start( $chat_button, FALSE, FALSE, 0 );

$chat_window->add($chat_vbox);
$chat_window->show_all;

$chat_button->signal_connect("clicked" => sub {
if ($chat_state eq 'Connect') {
$chat_button->set_label('Disconnect');
$chat_state='Disconnect';
$chat_start = 1;
#$chat_entry->set_editable(1);
#$chat_entry->grab_focus;
#$chat_entry->signal_handler_unblock ($chat_send_sig);
$post = 1;
}
else {
$chat_button->set_label('Connect');
$chat_state='Connect';
$chat_start = 0;
#$chat_entry->set_editable(0);
#$chat_entry->grab_focus;
#$chat_entry->signal_handler_block ($chat_send_sig);
$post = 5;
}
});

return 1;
}

#-------------------Post to Textview-------------------
sub post {
#my ($name, $msg) = @_;
my @time = gmtime;
my $hour = $time[2];
my $min = $time[1];
my $sec = $time[0];
$hour = "0$time[2]" if $time[2] < 10;
$min = "0$time[1]" if $time[1] < 10;
$sec = "0$time[0]" if $time[0] < 10;
my $post_time = "($hour:$min:$sec)";

my $chat_buffer = $chat_textview->get_buffer;
#connecting
if ($post == 1){
$chat_buffer->insert( $chat_buffer->get_end_iter, "Connecting
to $irc_server..\n" );
$post = 0;
print CHAT "Connecting to $irc_server..\n" if $job == 3;
}
#Connected
if ($post == 2){
$chat_buffer->insert( $chat_buffer->get_end_iter, "Connected
to $irc_server\n" );
$chat_entry->set_editable(1);
$chat_entry->grab_focus;
$chat_entry->signal_handler_unblock ($chat_send_sig);
$post = 0;
print CHAT "Connected to $irc_server\n" if $job == 3;
}
#Joined
if ($post == 3){
if ($name ne $nick){
$chat_buffer->insert_with_tags( $chat_buffer-
>get_end_iter, "$name Joined $channel$post_time\n", $chat_buffer-
>create_tag($tag, foreground=>'red'));
}
else{
$chat_buffer->insert( $chat_buffer->get_end_iter, "$name
Joined $channel$post_time\n");
}
$post = 0;
print CHAT "$name Joined $channel$post_time\n" if $job == 3;
}
#Users
if ($post == 4){
#print "$list\n";
$chat_buffer->insert( $chat_buffer->get_end_iter, "Users on
$channel: $list\n" );
$post = 0;
print CHAT "Users on $channel: $list\n" if $job == 3;
}
#disconnect
if ($post == 5){
$chat_buffer->insert( $chat_buffer->get_end_iter,
"Disconnecting$post_time\n" );
$chat_entry->set_editable(0);
$chat_entry->grab_focus;
$chat_entry->signal_handler_block ($chat_send_sig);
$post = 0;
print CHAT "Disconnecting$post_time\n" if $job == 3;
}
#Posts
if ($post == 6){
if ($name ne $nick){
$chat_buffer->insert_with_tags( $chat_buffer-
>get_end_iter, "$name$post_time: $msg", $chat_buffer->create_tag($tag,
foreground=>'red'));
}
else{
$chat_buffer->insert( $chat_buffer->get_end_iter, "$name
$post_time: $msg\n");
}
print CHAT "$name$post_time: $msg\n" if $job == 3;
$post = 0;
}
#Disconnected
if ($post == 7){
$chat_buffer->insert( $chat_buffer->get_end_iter,
"Disconnected->Reconnecting$post_time\n");
print CHAT "Disconnected->Reconnecting$post_time\n" if $job ==
3;
$post = 0;
}
#Nick taken
if ($post == 8){
$chat_buffer->insert( $chat_buffer->get_end_iter, "Nick is
Taken->Please Change\n");
$chat_entry->set_editable(0);
$chat_entry->grab_focus;
$chat_entry->signal_handler_block ($chat_send_sig);
$chat_start = 0;
$chat_state = 'Connect';
$chat_button->set_label($chat_state);
$chat_buffer->insert( $chat_buffer->get_end_iter, "Nick is
Taken->Please Change\n" );
print CHAT "Connecting to $irc_server..\n" if $job == 3;
$post = 0;
}
#Quit
if ($post == 9){
$chat_buffer->insert_with_tags( $chat_buffer->get_end_iter,
"$name has QUIT$post_time\n", $chat_buffer->create_tag($tag,
foreground=>'red'));
print CHAT "$name has QUIT$post_time\n" if $job == 3;
$post = 0;
}

return 1;
}

##################################################
####################Threads####################
sub chat{
while (1){
my $conn;
goto END if $die == 1;
if ($chat_start == 1){
print "starting...\n";

$conn = $irc->newconn(Server => $irc_server,
Port => 6667,
Nick => $nick,
Ircname => "CoCoNUE Member $nick")
or die "Can't connect to IRC server\n";

#Install Handlers
$conn->add_handler('cping',
\&on_ping); #
$conn->add_handler('crping',
\&on_ping_reply); #
$conn->add_handler('join',
\&on_join); #3
$conn->add_handler('quit',
\&on_quit); #9
$conn->add_handler('public',
\&on_public); #6

$conn->add_global_handler([ 251,252,253,254,302,255 ],
\&on_init);
$conn->add_global_handler('disconnect',
\&on_disconnect); #7
$conn->add_global_handler(376,
\&on_connect); #2
$conn->add_global_handler(433,
\&on_nick_taken); #8
$conn->add_global_handler(353,
\&on_names); #4

for (;;){
$irc->do_one_loop;
#print "Looped: Reading\n";
if ($chat_start == 2){
#print "Looped: Sending\n";
$conn->privmsg("$channel", "$msg");
$chat_start = 1 if $chat_start != 0;
}
goto END if $die == 1;
last if $chat_start == 0;
}
$irc->removeconn($conn);
}
}
END:
}

#-------------------Handlers-------------------

# What to do when the bot successfully connects.
sub on_connect {
my $self = shift;
$post = 2;
sleep 1;
print "Joining $channel...\n";
$self->join("$channel");
}


# Handles some messages you get when you connect:::For testing
sub on_init {
my ($self, $event) = @_;
my (@args) = ($event->args);
shift (@args);
print "*** @args\n";
}

# What to do when someone leaves a channel the bot is on.
sub on_quit {
my ($self, $event) = @_;
#my ($channel) = ($event->to)[0];
$name = $event->nick;

$post = 9;
printf "*** %s has left channel %s\n", $event->nick, $channel;
}

# What to do when someone joins a channel the bot is on.
sub on_join {
my ($self, $event) = @_;
#my ($channel) = ($event->to)[0];
$name = $event->nick;

$post = 3;
sleep 1;
printf "*** %s (%s) has joined channel %s\n",
$event->nick, $event->userhost, $channel;

if ($event->userhost =~ /^corbeau\@.*execpc\.com/) { # Auto-ops
anyone who
$self->mode("#IRC.pm", "+o", $event->nick); # matches hostmask.
}
}

# Prints the names of people in a channel when we enter.
sub on_names {
my ($self, $event) = @_;
my (@list) = ($event->args); # eat yer heart out, mjd!
# splice() only works on real arrays. Sigh.
($channel, @list) = splice @list, 2;
$list = join(" ", @list);
print "$list\n";

$post = 4;
print "Users on $channel: @list\n";
}

# Yells about incoming CTCP PINGs.
sub on_ping {
my ($self, $event) = @_;
my $name = $event->nick;

$self->ctcp_reply($name, join (' ', ($event->args)));
print "*** CTCP PING request from $name received\n";
}

# Gives lag results for outgoing PINGs.
sub on_ping_reply {
my ($self, $event) = @_;
my ($args) = ($event->args)[1];
my ($name) = $event->nick;

$args = time - $args;
print "*** CTCP PING reply from $name: $args sec.\n";
}

# Change our nick if someone stole it.
sub on_nick_taken {
my ($self) = shift;
#$chat_start = 0;
#$chat_state = 'Connect';
$post = 8;
#$self->nick(substr($self->nick, -1) . substr($self->nick, 0, 8));
}

# Reconnect to the server when we die.
sub on_disconnect {
my ($self, $event) = @_;

$post = 7;
print "Disconnected from ", $event->from(), " (",
($event->args())[0], "). Attempting to reconnect...\n";
$self->connect();
}

# What to do when we receive channel text.
sub on_public {
my ($self, $event) = @_;
my @to = $event->to;
my ($them, $me) = ($event->nick, $self->nick);
($msg) = ($event->args);
$name = $event->nick;
#$msg = $arg;

$post = 6;
# Note that $event->to() returns a list (or arrayref, in scalar
# context) of the message's recipients, since there can easily be
# more than one.

print "<$them> $msg\n";
}