package appwin; use Scalar::Util; use base KGS::Listener; use base gtk::widget; my %context_id; # static method to request the userimage and call the cb when it's available. sub userpic { my ($name, $cb) = @_; $self->get_userpic ($name, $cb); } sub status { my ($type, $text) = @_; $self->{status}->pop($context_id{$type}) if $context_id{$type}; $self->{status}->push($context_id{$type} ||= $self->{status}->get_context_id($type), $text) if $text; } sub new { my $self = shift; $self = $self->SUPER::new(@_); $appwin::self = $self; # singleton Scalar::Util::weaken $appwin::self; $self->{conn} = new KGS::Protocol; KGS::Listener::Debug->new->listen($self->{conn}, "any"); #d# debug only :) $self->listen($self->{conn}, qw(login userpic idle_warn)); $self->{roomlist} = new roomlist conn => $self->{conn}; $self->{window} = new Gtk2::Window 'toplevel'; $self->{window}->set_title('kgsueme'); gtk::state $self->{window}, "main::window", undef, window_size => [400, 400]; $self->{window}->signal_connect(delete_event => sub { main_quit Gtk2; 1 }); $self->{window}->add(my $vbox = new Gtk2::VBox); $vbox->pack_start(($buttonbox = new Gtk2::HButtonBox), 0, 1, 0); $buttonbox->set_spacing(0); my $button = sub { $buttonbox->add(my $button = new Gtk2::Button $_[0]); signal_connect $button clicked => $_[1]; }; $button->("Login", sub { $self->login; }); $button->("Roomlist", sub { $self->{roomlist}->show; }); $button->("Save Config & Layout", \&util::save_config); $button->("Quit", sub { main_quit Gtk2 }); $vbox->pack_start((my $hbox = new Gtk2::HBox), 0, 1, 0); $hbox->add(new Gtk2::Label "Login"); $hbox->add($self->{login} = new_with_max_length Gtk2::Entry 12); $self->{login}->set_text($::config->{login}); if ($::HACK) { $self->{login}->signal_connect(activate => sub { $self->{conn}{name} = $self->{login}->get_text; }); } $hbox->add(new Gtk2::Label "Password"); $hbox->add($self->{password} = new Gtk2::Entry); $self->{password}->set_visibility(0); $self->{gamelist} = new gamelist conn => $self->{conn}; $vbox->pack_start ($self->{gamelist}->widget, 1, 1, 0); $appwin::gamelist = $self->{gamelist}; Scalar::Util::weaken $appwin::gamelist; $vbox->pack_start(($self->{status} = new Gtk2::Statusbar), 0, 1, 0); $self->{window}->show_all; $self; } sub login { my ($self) = @_; $self->{conn}->disconnect; # initialize new socket and connection #my $sock = new IO::Socket::INET PeerHost => "kgs.kiseido.com", PeerPort => "2379" my $sock = new IO::Socket::INET PeerHost => $ENV{KGSHOST} || "kgs.kiseido.com", PeerPort => "2379" or die; $sock->blocking(1); $self->{conn}->handshake($sock); $sock->blocking(0); my $input; $input = add_watch Glib::IO fileno $sock, [G_IO_IN, G_IO_ERR, G_IO_HUP], sub { # this is dorked my $buf; my $len = sysread $sock, $buf, 16384; if ($len) { $self->{conn}->feed_data($buf); } elsif (defined $len || (!$!{EINTR} and !$!{EAGAIN})) { warn "disconnected";#d# remove Glib::Source $input; $self->event_disconnect; } 1; }, G_PRIORITY_HIGH; # now login $ENV{KGSUEME_CLIENTVER} = "1.4.1_01:Swing app:Sun Microsystems Inc."; # he asked for it...#d# $self->{conn}->login($ENV{KGSUEME_CLIENTVER} || "kgsueme $VERSION $^O", # allow users to overwrite $self->{login}->get_text, $self->{password}->get_text); } sub inject_idle_warn { my ($self, $msg) = @_; $self->send ("idle_reset"); } sub inject_login { my ($self, $msg) = @_; appwin::status("login", "logged in as '$self->{conn}{name}' with status '$msg->{result}' ('$msg->{reason}')"); $::config->{login} = $self->{conn}{name}; if ($msg->{success}) { # auto-join for (values %{$::config->{rooms}}) { $self->{roomlist}->join_room($_); } sound::play 3, "connect"; } elsif ($msg->{result} eq "user unknown") { sound::play 2, "user_unknown"; } else { sound::play 2, "warning"; } } my %userpic; my %userpic_cb; sub get_userpic { my ($self, $name, $cb) = @_; if (exists $userpic{$name}) { $cb->($userpic{$name}); } else { if (!exists $userpic_cb{$name}) { # after 10 seconds, flush callbacks $self->send (req_pic => name => $name); add Glib::Timeout 10000, sub { $_->() for @{delete $userpic_cb{$name} || []}; 0; }; } push @{$userpic_cb{$name}}, $cb; } } sub inject_userpic { my ($self, $msg) = @_; $userpic{$msg->{name}} = $msg->{data}; $_->($userpic{$msg->{name}}) for @{delete $userpic_cb{$msg->{name}} || []}; } sub event_disconnect { } 1;