Textview not scrolling in Client



I have been struggling with this and I just cant seem to figure what the problem is. 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 where mark is defined as 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 am wondering if the word wrapping is causing it since this behavior is true for a single unwrapped line. I would appreciate any help on this since it seems like such a simple thing and I cant figure it.

#!/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 $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;
            $post = 1;
        }
        else {
            $chat_button->set_label('Connect');
            $chat_state='Connect';
            $chat_start = 0;
            $post = 5;
        }
    });

    return 1;

}

#-------------------Post to Textview-------------------
sub post {
    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;
    }
    #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;
    }
    #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;
    }
    #Users
    if ($post == 4){
        $chat_buffer->insert( $chat_buffer->get_end_iter, "Users on $channel: $list\n" );
        $post = 0;
    }
    #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;
    }
    #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");
        }
        $post = 0;
    }
    #Disconnected
    if ($post == 7){
        $chat_buffer->insert( $chat_buffer->get_end_iter,
"Disconnected->Reconnecting$post_time\n");
        $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" );
        $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'));
        $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;
                if ($chat_start == 2){
                    $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) = @_;
    $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) = @_;
    $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";
}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]