Skip to content

Instantly share code, notes, and snippets.

@TingPing
Last active October 20, 2016 17:32
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save TingPing/cde2a83448cf1b98d09d to your computer and use it in GitHub Desktop.
Save TingPing/cde2a83448cf1b98d09d to your computer and use it in GitHub Desktop.
use strict;
use warnings;
use Glib;
use Gtk2 -init;
##############################
# Copyright 2012, Colby Vanden Toorn
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
##############################
# Hilight Buffer Size is how large (in lines) the buffer for each pane should be.
# Below you will find the general structure of the hooks, You can view the
# available hooks under settings -> advanced -> text events. "PrependChan"
# is to show what channel the message came from, obviously this is only
# useful for some things such as channel hilights.
my @gtk;
my %conf = (
HILIGHT_BUFFER_SIZE => 20,
);
my @Hooks = (
{
Event => 'Channel Ban',
LPane => 1,
RPane => 0,
PrependChan => 1,
},
{
Event => 'Server Text',
LPane => 1,
RPane => 0,
},
{
Event => 'Server Notice',
LPane => 1,
RPane => 0,
},
{
Event => 'Channel Notice',
LPane => 0,
RPane => 1,
},
{
Event => 'Notice',
LPane => 0,
RPane => 1,
},
{
Event => 'Channel Action Hilight',
LPane => 0,
RPane => 1,
PrependChan => 1,
},
{
Event => 'Channel Msg Hilight',
LPane => 0,
RPane => 1,
PrependChan => 1,
},
# Whois events...
{ Event => 'WhoIs Authenticated', LPane => 0, RPane => 1 },
{ Event => 'WhoIs Away Line', LPane => 0, RPane => 1 },
{ Event => 'WhoIs Channel/Oper Line', LPane => 0, RPane => 1 },
{ Event => 'WhoIs End', LPane => 0, RPane => 1 },
{ Event => 'WhoIs Identified', LPane => 0, RPane => 1 },
{ Event => 'WhoIs Idle Line', LPane => 0, RPane => 1 },
{ Event => 'WhoIs Idle Line with Signon', LPane => 0, RPane => 1 },
{ Event => 'WhoIs Name Line', LPane => 0, RPane => 1 },
{ Event => 'WhoIs Real Host', LPane => 0, RPane => 1 },
{ Event => 'WhoIs Server Line', LPane => 0, RPane => 1 },
{ Event => 'WhoIs Special', LPane => 0, RPane => 1 },
# Other random things
{ Event => 'Ping Reply', LPane => 0, RPane => 1 },
{ Event => 'CTCP Generic', LPane => 0, RPane => 1 },
{ Event => 'CTCP Generic to Channel', LPane => 0, RPane => 1 },
# Supress these
{ Event => 'Invite', Return => Xchat::EAT_XCHAT }
);
my %colors;
loadColors();
createNewPane();
addHooks();
Xchat::register("InfoPanes", "1.0.0", "Displays custom info in two display panes");
sub addHooks {
foreach my $h (@Hooks) {
Xchat::hook_print($h->{Event}, \&pushMsgBox, { data => $h });
}
}
sub getTextFormat {
my $h = shift;
if ($h->{Format}) {
return $h->{Format};
} else {
return Xchat::get_info("event_text $h->{Event}");
}
}
sub pushMsgBox {
my $hook = $_[1];
my $format = getTextFormat($hook);
my $context = Xchat::get_context();
if ($hook->{PrependChan}) {
$format = Xchat::get_info("channel") . " $format";
}
$format =~ s/%[A-Z]\d?\d?//g; # For now...
$format =~ s/\$t/ /g;
while ($format =~ /\$(\d)/g) {
if (defined($_[0][$1 - 1])) {
my $v = $_[0][$1 - 1];
$format =~ s/\$$1/$v/g;
} else {
$format =~ s/\$$1//g;
}
}
Xchat::strip_code($format);
pushMessage(0, $format) if $hook->{LPane};
pushMessage(1, $format) if $hook->{RPane};
return Xchat::EAT_NONE;
}
sub topDownSearch {
my $type = shift;
my $GObject = Glib::Object->new_from_pointer( Xchat::get_info( "win_ptr" ), 0 );
my @containers = ($GObject);
while( @containers ) {
my $container = shift @containers;
for my $child ( $container->get_children ) {
if( $child->isa($type) ) {
return $child;
} elsif( $child->isa( "Gtk2::Container" ) ) {
push @containers, $child;
}
}
}
return 0;
}
sub bottomUpSearch {
for (my ($type, $root) = @_; !$root->isa($type) || return $root; $root = $root->parent) {}
}
sub createNewPane {
# Create the two panes
my $sc1 = Gtk2::ScrolledWindow->new;
my $sc2 = Gtk2::ScrolledWindow->new;
my $tv2 = Gtk2::TextView->new;
my $tv1 = Gtk2::TextView->new;
my $tb2 = $tv2->get_buffer;
my $tb1 = $tv1->get_buffer;
$sc1->set_policy("never", "always");
$sc2->set_policy("never", "always");
$sc1->add($tv1);
$sc2->add($tv2);
$tv1->set_wrap_mode("word_char");
$tv2->set_wrap_mode("word_char");
# Now we will create a horizontal pane to display the scroll windows
# side by side, with boarders.
my $displayPane = Gtk2::HPaned->new;
# Setup the frames.. (possibly change to scroll window shadow....
my $frame1 = Gtk2::Frame->new();
my $frame2 = Gtk2::Frame->new();
$frame1->set_shadow_type("in");
$frame2->set_shadow_type("in");
# Pack the horizontal pane
$frame1->add($sc1);
$frame2->add($sc2);
$displayPane->pack1($frame1, 1, 1);
$displayPane->pack2($frame2, 1, 1);
# Switch some things around...
my $vpane = Gtk2::VPaned->new;
my $mainPane = topDownSearch("Gtk2::HPaned");
my $parent = $mainPane->parent;
$parent->remove($mainPane);
$parent->add($vpane);
# Pack some things into the new pane
$vpane->pack1($displayPane, 1, 1);
$vpane->pack2($mainPane, 1, 0);
# And finally have the objects show.
$tv1->show;
$sc1->show;
$tv2->show;
$sc2->show;
$frame1->show;
$frame2->show;
$displayPane->show;
$vpane->show;
# disable childs ability to expand etc
$frame1->set_resize_mode("queue");
$frame2->set_resize_mode("queue");
# Set background colors
my $bgColor = Gtk2::Gdk::Color->new($colors{259}{R}, $colors{259}{G}, $colors{259}{B});
$tv1->modify_base("normal", $bgColor);
$tv2->modify_base("normal", $bgColor);
# Copy the stuff over to a global variable
$gtk[0]{TextBuffer} = $tb1;
$gtk[1]{TextBuffer} = $tb2;
$gtk[0]{ScrolledWindow} = $sc1;
$gtk[1]{ScrolledWindow} = $sc2;
$gtk[0]{TextView} = $tv1;
$gtk[1]{TextView} = $tv2;
# Fill buffers with empty lines
$tb1->set_text("\r\n" x 20);
$tb2->set_text("\r\n" x 20);
# Don't want them editable..
$tv1->set_editable(0);
$tv2->set_editable(0);
return 1;
}
sub pushMessage {
my ($n, $message) = @_;
my $buff = $gtk[$n]{TextBuffer};
$buff->insert($buff->get_end_iter, "\r\n$message");
while ($buff->get_line_count > $conf{HILIGHT_BUFFER_SIZE}) {
$buff->delete($buff->get_start_iter, $buff->get_iter_at_line(1));
}
# Should change this so it wont bottom unless it was just at the bottom
bottomScrollbar($gtk[$n]{ScrolledWindow}->get_vadjustment);
return 1;
}
sub bottomScrollbar {
my $scrollbar = shift;
$scrollbar->value($scrollbar->upper);
$scrollbar->changed;
$scrollbar->value_changed;
return 1;
}
sub loadColors {
my $confDir = Xchat::get_info('xchatdir');
my $file;
if (open($file, "<", "$confDir/colors.conf")) {
foreach my $line (<$file>) {
$line =~ /color_(.*?) = (....) (....) (....)\r?\n/;
$colors{$1}{R} = hex($2);
$colors{$1}{G} = hex($3);
$colors{$1}{B} = hex($4);
}
close $file;
return 1;
} else {
# Couldn't open file...
return 0;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment