ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/kgsueme/kgsueme/app.pl
Revision: 1.18
Committed: Mon May 31 03:28:15 2004 UTC (20 years ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.17: +1 -0 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 pcg 1.1 package app;
2    
3     use KGS::Protocol::Client;
4    
5     use Scalar::Util;
6    
7     use base KGS::Listener;
8 pcg 1.9
9     use Glib::Object::Subclass
10     Gtk2::Window;
11 pcg 1.1
12     my %context_id;
13    
14 pcg 1.9 our $self;
15    
16 pcg 1.1 sub status {
17     my ($type, $text) = @_;
18    
19 pcg 1.9 $::self->{status}->pop ($context_id{$type}) if $context_id{$type};
20     $::self->{status}->push ($context_id{$type} ||= $::self->{status}->get_context_id ($type), $text) if $text;
21 pcg 1.1 }
22    
23     sub new {
24 pcg 1.10 my ($self, %arg) = @_;
25 pcg 1.9 $self = $self->Glib::Object::new;
26 pcg 1.10 $self->{$_} = delete $arg{$_} for keys %arg;
27 pcg 1.1
28 pcg 1.9 Scalar::Util::weaken ($::self = $self); # singleton...
29 pcg 1.1
30     $self->{conn} = new KGS::Protocol::Client;
31    
32 pcg 1.14 $self->listen ($self->{conn}, qw(login userpic idle_warn msg_chat chal_defaults));
33 pcg 1.1
34     $self->{roomlist} = new roomlist conn => $self->{conn}, app => $self;
35    
36 pcg 1.9 $self->set_title ('kgsueme');
37 pcg 1.13 gtk::state $self, "main::window", undef, window_size => [400, 500];
38 pcg 1.9 $self->signal_connect (destroy => sub { %{$_[0]} = () });
39     $self->signal_connect (delete_event => sub { main_quit Gtk2; 1 });
40 pcg 1.1
41 pcg 1.9 $self->add (my $vbox = new Gtk2::VBox);
42 pcg 1.1
43 pcg 1.9 $vbox->pack_start (($buttonbox = new Gtk2::HButtonBox), 0, 1, 0);
44     $buttonbox->set_spacing (0);
45 pcg 1.1
46     my $button = sub {
47 pcg 1.9 $buttonbox->add (my $button = new Gtk2::Button $_[0]);
48 pcg 1.1 signal_connect $button clicked => $_[1];
49     };
50    
51     $button->("Login", sub { $self->login; });
52     $button->("Roomlist", sub { $self->{roomlist}->show; });
53     $button->("Save Config & Layout", \&util::save_config);
54     $button->("Quit", sub { main_quit Gtk2 });
55    
56 pcg 1.9 $vbox->pack_start ((my $hbox = new Gtk2::HBox), 0, 1, 0);
57 pcg 1.1
58 pcg 1.9 $hbox->add (new Gtk2::Label "Login");
59 pcg 1.1
60 pcg 1.9 $hbox->add ($self->{login} = new_with_max_length Gtk2::Entry 12);
61     $self->{login}->set_text ($::config->{login});
62 pcg 1.1
63 pcg 1.9 $hbox->add (new Gtk2::Label "Password");
64     $hbox->add ($self->{password} = new Gtk2::Entry);
65 root 1.16 $self->{password}->set (visibility => 0, is_focus => 1);
66     $self->{password}->signal_connect (activate => sub { $self->login });
67 pcg 1.1
68 pcg 1.13 $vbox->pack_start ((my $vpane = new Gtk2::VPaned), 1, 1, 0);
69     $vpane->set (position_set => 1);
70     gtk::state $vpane, "main::vpane", undef, position => 250;
71    
72     $vbox->pack_start(($self->{status} = new Gtk2::Statusbar), 0, 1, 0);
73    
74 pcg 1.1 $self->{gamelist} = new gamelist conn => $self->{conn}, app => $self;
75 pcg 1.13 $vpane->pack1 ($self->{gamelist}, 1, 1);
76    
77     $self->{rooms} = new Gtk2::Notebook;
78 root 1.18 $self->{rooms}->set (enable_popup => 1, scrollable => 1);
79 pcg 1.1
80 pcg 1.13 $vpane->pack2 ($self->{rooms}, 1, 1);
81 pcg 1.1
82 pcg 1.9 $self->show_all;
83 pcg 1.1
84     $self;
85     }
86    
87     sub login {
88     my ($self) = @_;
89    
90     $self->{conn}->disconnect;
91    
92     # initialize new socket and connection
93 pcg 1.12 my $sock = new IO::Socket::INET PeerHost => KGS::Protocol::KGSHOST, PeerPort => KGS::Protocol::KGSPORT
94 pcg 1.7 or die "connect: $!";
95 pcg 1.1
96 root 1.15 $sock->blocking (1);
97     $self->{conn}->handshake ($sock);
98     $sock->blocking (0);
99 pcg 1.1
100     my $input; $input = add_watch Glib::IO fileno $sock, [G_IO_IN, G_IO_ERR, G_IO_HUP], sub {
101     # this is dorked
102     my $buf;
103     my $len = sysread $sock, $buf, 16384;
104     if ($len) {
105 root 1.15 $self->{conn}->feed_data ($buf);
106 pcg 1.1 } elsif (defined $len || (!$!{EINTR} and !$!{EAGAIN})) {
107     warn "disconnected";#d#
108     remove Glib::Source $input;
109     $self->event_disconnect;
110     }
111     1;
112     }, G_PRIORITY_HIGH;
113    
114     # now login
115     $ENV{KGSUEME_CLIENTVER} = "1.4.1_01:Swing app:Sun Microsystems Inc."; # he asked for it...#d#
116     $self->{conn}->login($ENV{KGSUEME_CLIENTVER} || "kgsueme $VERSION $^O", # allow users to overwrite
117     $self->{login}->get_text,
118     $self->{password}->get_text);
119     }
120    
121 pcg 1.5 sub inject_login {
122 pcg 1.1 my ($self, $msg) = @_;
123    
124 pcg 1.5 $self->{name} = $self->{conn}{name};
125 pcg 1.1
126 pcg 1.5 $::config->{login} = $self->{name};
127 pcg 1.1
128 pcg 1.6 app::status("login", "logged in as '$self->{name}' with status '$msg->{message}' ('$msg->{reason}')");
129 pcg 1.1
130     if ($msg->{success}) {
131     # auto-join
132     $self->open_room (%$_) for values %{$::config->{rooms}};
133    
134     sound::play 3, "connect";
135     } elsif ($msg->{result} eq "user unknown") {
136     sound::play 2, "user_unknown";
137     } else {
138     sound::play 2, "warning";
139     }
140     }
141    
142 pcg 1.5 sub inject_idle_warn {
143     my ($self, $msg) = @_;
144    
145     $self->send ("idle_reset");
146     }
147    
148     sub inject_msg_chat {
149     my ($self, $msg) = @_;
150    
151     if ((lc $msg->{name2}) eq (lc $self->{name})) {
152     unless ($self->{user}{lc $msg->{name}}) {
153     $self->open_user (name => $msg->{name})->inject ($msg);
154 root 1.17 sound::play 2, "ring";
155 pcg 1.5 }
156     }
157     }
158    
159 pcg 1.14 sub inject_chal_defaults {
160     my ($self, $msg) = @_;
161    
162     $self->{defaults} = $msg->{defaults};
163     }
164    
165 pcg 1.1 my %userpic;
166     my %userpic_cb;
167    
168     # static method to request the userimage and call the cb when it's available.
169     sub userpic {
170     my ($self, $name, $cb) = @_;
171     $self->get_userpic ($name, $cb);
172     }
173    
174     sub get_userpic {
175     my ($self, $name, $cb) = @_;
176    
177     if (exists $userpic{$name}) {
178     $cb->($userpic{$name});
179     } else {
180     if (!exists $userpic_cb{$name}) {
181     # after 10 seconds, flush callbacks
182     $self->send (req_pic => name => $name);
183     add Glib::Timeout 10000, sub {
184     $_->() for @{delete $userpic_cb{$name} || []};
185     0;
186     };
187     }
188     push @{$userpic_cb{$name}}, $cb;
189     }
190     }
191    
192     sub inject_userpic {
193     my ($self, $msg) = @_;
194    
195     $userpic{$msg->{name}} = $msg->{data};
196     $_->($userpic{$msg->{name}}) for @{delete $userpic_cb{$msg->{name}} || []};
197     }
198    
199 root 1.15 sub event_disconnect {
200     $_->destroy
201     for values %{delete $self->{game} or {}}, values %{delete $self->{room} or {}};
202     }
203 pcg 1.1
204     sub open_game {
205     my ($self, %arg) = @_;
206    
207     ($self->{game}{$arg{channel}} ||= new game %arg, conn => $self->{conn}, app => $self)
208     ->join;
209 pcg 1.4 Scalar::Util::weaken $self->{game}{$arg{channel}};
210 pcg 1.2 $self->{game}{$arg{channel}};
211 pcg 1.1 }
212    
213     sub open_room {
214     my ($self, %arg) = @_;
215    
216 pcg 1.13 my $room = $self->{room}{$arg{channel}} ||= do {
217     my $room = new room %arg, conn => $self->{conn}, app => $self;
218     $room->show_all;
219     $self->{rooms}->append_page ($room, new Gtk2::Label $room->{name});
220     $room;
221     };
222 pcg 1.8 Scalar::Util::weaken $self->{room}{$arg{channel}};
223 pcg 1.13
224     $room->join;
225 pcg 1.2 $self->{room}{$arg{channel}};
226     }
227    
228     sub open_user {
229     my ($self, %arg) = @_;
230    
231 pcg 1.3 ($self->{user}{lc $arg{name}} ||= new user %arg, conn => $self->{conn}, app => $self)
232 pcg 1.2 ->join;
233 pcg 1.4 Scalar::Util::weaken $self->{user}{lc $arg{name}};
234 pcg 1.3 $self->{user}{lc $arg{name}};
235 pcg 1.2 }
236    
237     sub do_command {
238     my ($self, $chat, $cmd, $arg, %arg) = @_;
239    
240 pcg 1.5 if ($cmd eq "say") {
241     if (my $context = $arg{game} || $arg{room} || $arg{user}) {
242 pcg 1.2 $context->say ($arg);
243     } else {
244     $chat->append_text ("\n<error>no context for message</error>");
245     }
246     } elsif ($cmd eq "whois" or $cmd eq "w") {
247     $self->open_user (name => $arg);
248     } else {
249     $chat->append_text ("\n<error>unknown command</error>");
250     }
251 pcg 1.1 }
252    
253     1;
254