use strict; use warnings; use Xchat qw(:all); use Glib qw(TRUE FALSE); use Gtk2 -init; my %prefix_color = ( purple => [ 0x9191, 0x0000, 0x9191 ], red => [ 0xaaaa, 0x0000, 0x0000 ], '@' => [ 0x6565, 0xc4c4, 0x0000 ], '%' => [ 0x4e4e, 0xf3f3, 0xf7f7 ], '+' => [ 0xb7b7, 0x8a8a, 0x0000 ], ); register( "Colored Userlist", "1.000003", "Color userlist nicks based on modes" ); $_ = Gtk2::Gdk::Color->new( @$_ ) for values %prefix_color; my %update_pending; sub get_ptr { if( $^O ne 'MSWin32' ) { return get_info "win_ptr"; } else { my $session = unpack( "P1532", pack( "L", get_context ) ); my $gui_address = unpack( "x1516L", $session ); my $session_gui = unpack( "P232", pack( "L", $gui_address ) ); my $win_ptr = unpack( "x8L", $session_gui ); return $win_ptr; } } sub get_user_list { my $widget = Glib::Object->new_from_pointer( get_ptr() , 0 ); my @candidates = ($widget); while( @candidates ) { my $candidate = shift @candidates; next unless $candidate->isa( "Gtk2::Widget" ); if( $candidate->get( "name" ) eq 'xchat-userlist' ) { return $candidate; } elsif ( $candidate->isa( "Gtk2::Container" ) ) { push @candidates, $candidate->get_children; } } return; } # changes the background color instead of the foreground { my $nick_col = get_user_list->get_column( 1 ); my ($renderer) = grep { $_->isa( 'Gtk2::CellRendererText' ) } $nick_col->get_cell_renderers; if( $renderer ) { $renderer->set( "font", "Monospace 10" ); # $nick_col->clear_attributes( $renderer ); # $nick_col->set_attributes( $renderer, 'text', 1, 'background-gdk', 4 ); } } # disable the icon column { my $pix_col = get_user_list->get_column( 0 ); my ($renderer) = grep { $_->isa( 'Gtk2::CellRendererPixbuf' ) } $pix_col->get_cell_renderers; if( $renderer ) { $pix_col->clear_attributes( $renderer ); } } # deal with changes that has happened while the tab is not focused # it needs to be done this way otherwise we will end up getting the wrong # model and change the userlist for the wrong channel hook_print( "Focus Tab", sub { my $ctx = get_context; if( $update_pending{ $ctx } ) { # prnt "Updating ul..."; delete $update_pending{ $ctx }; hook_timer( 100, sub { update_ul_colors(); return REMOVE; }); } return EAT_NONE; }); hook_command( "UL", sub { update_ul_colors(); return EAT_XCHAT; }); hook_print( "You Join", sub { if( get_context == find_context ) { # TODO: find a better method to determine when xchat has finished # fetching the user information, probably "End of Who" hook_timer( 5_000, sub { update_ul_colors(); return REMOVE; }); } else { $update_pending{ get_context() } = 1; } return EAT_NONE; }); hook_server( "MODE", sub { my $target = $_[0][2]; if( $target =~ /^[#&]/ ) { my $context = find_context( $target, get_info( "server" ) ); if( $context == find_context ) { #prnt "Doing update..."; hook_timer( 0, sub { set_context $context; update_ul_colors(); return REMOVE; }); } else { #prnt "Queuing update"; $update_pending{ $context } = 1; } } return EAT_NONE; }); sub update_ul_colors { my $user_list = get_user_list; #prnt "Channel: " . get_info "channel"; #prntf "Current: %s Front: %s", get_context(), find_context(); if( $user_list ) { my $model = $user_list->get_model; my $nick_prefixes = context_info->{nickprefixes}; #prnt "Iterating ..."; $model->foreach( sub { my ($m, $p, $i) = @_; my ($nick) = $m->get( $i, 1 ); #prnt "Starting Nick: $nick"; $nick =~ s/^[^\x41-\x5A\x61-\x7A\x5B-\x60]+//; my $nick_info = user_info( $nick ); my $prefix = $nick_info->{prefix}; #use Data::Dumper; #prnt Dumper( $nick_info ); if( $prefix ) { my $color = $prefix_color{ $prefix }; if( !$color ) { my $diff = index( $nick_prefixes, '@' ) - index( $nick_prefixes, $prefix ); if( $diff == 1 ) { $color = $prefix_color{red}; } elsif( $diff == 2 ) { $color = $prefix_color{purple}; } # prnt "Diff: $diff" } # prnt "Color: $color"; if( $color ) { my $old_color = $m->get( $i, 4 ); if( ($old_color && !$old_color->equal( $color ) ) || !$old_color ) { $m->set( $i, 4, $color ); } } } $prefix ||= " "; #prnt qq{Nick: $nick | Prefix: "$prefix"}; $m->set( $i, 1, "$prefix$nick" ); return FALSE; }); } else { prnt "Couldn't find user list"; } return EAT_NONE; }