]> git.cworth.org Git - grrobot/blob - src/grrobot.c
Added drag-and-drop (works but for handling queued notices).
[grrobot] / src / grrobot.c
1 /* grrobot - Ricochet Robot using GTK+ and Xr
2  *
3  * Copyright © 2003 Carl Worth
4  *
5  * Permission to use, copy, modify, distribute, and sell this software
6  * and its documentation for any purpose is hereby granted without
7  * fee, provided that the above copyright notice appear in all copies
8  * and that both that copyright notice and this permission notice
9  * appear in supporting documentation, and that the name of Carl Worth
10  * not be used in advertising or publicity pertaining to distribution
11  * of the software without specific, written prior permission.
12  * Carl Worth makes no representations about the suitability of this
13  * software for any purpose.  It is provided "as is" without express
14  * or implied warranty.
15  * 
16  * CARL WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
18  * NO EVENT SHALL CARL WORTH BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
20  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
21  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23  *
24  * Author: Carl Worth <carl@theworths.org>
25  */
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <gtk/gtk.h>
34
35 #include "grr_board_view.h"
36 #include "args.h"
37
38 typedef struct grr_game {
39     rr_client_t *client;
40     rr_board_t *board;
41
42     GtkWidget *window;
43     GtkWidget *board_view;
44     GtkTextBuffer *message_buffer;
45     GtkWidget *message_view;
46     GtkWidget *command_entry;
47     GtkTextIter message_iter;
48 } grr_game_t;
49
50 static int
51 grr_game_start_gui (grr_game_t *game);
52
53 static void
54 grr_game_read_callback (gpointer data,
55                         gint fd,
56                         GdkInputCondition condition);
57
58 static void
59 grr_game_read_notices (grr_game_t *game);
60
61 int 
62 main (int argc, char **argv)
63 {
64     args_t args;
65     rr_status_t status;
66     grr_game_t game;
67
68     char *diagram;
69
70     gtk_init (&argc, &argv);
71     
72     args_parse (&args, argc, argv);
73
74     game.client = rr_client_create (args.host, args.port, args.user);
75     if (game.client == NULL) {
76         fprintf (stderr, "Failed connecting to %s:%s as %s\n",
77                  args.host, args.port, args.user);
78         return 1;
79     }
80
81     status = rr_client_join (game.client, args.game);
82     if (status == RR_STATUS_NO_GAME) {
83         status = rr_client_new (game.client, args.game);
84     }
85
86     game.board = rr_board_create (16, 16);
87
88     gdk_input_add (rr_client_fd (game.client),
89                    GDK_INPUT_READ,
90                    grr_game_read_callback,
91                    &game);
92
93     rr_client_show (game.client, &diagram);
94     rr_board_parse (game.board, diagram);
95     free (diagram);
96
97     return grr_game_start_gui (&game);
98 }
99
100 static void
101 grr_game_read_callback (gpointer data,
102                       gint fd,
103                       GdkInputCondition condition)
104 {
105     grr_game_t *game = data;
106
107     grr_game_read_notices (game);
108 }
109
110 static void
111 grr_game_read_notices (grr_game_t *game)
112 {
113     rr_board_t *board = game->board;
114     rr_status_t status;
115     char **notice_s;
116     rr_notice_t *notice;
117     int i;
118
119     while (rr_client_notice_pending (game->client)) {
120         status = rr_client_next_notice (game->client, &notice_s);
121         if (status) {
122             fprintf (stderr, "Error during rr_client_notice: %s\n",
123                      rr_status_str (status));
124             gtk_exit (1);
125             return;
126         }
127         for (i=0; notice_s[i]; i++) {
128             gtk_text_buffer_insert_at_cursor (game->message_buffer, notice_s[i], -1);
129             gtk_text_buffer_insert_at_cursor (game->message_buffer, " ", -1);
130         }
131         gtk_text_buffer_insert_at_cursor (game->message_buffer, "\n", -1);
132         gtk_text_buffer_get_iter_at_offset (game->message_buffer,
133                                             &game->message_iter,
134                                             -1);
135         gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (game->message_view),
136                                       &game->message_iter,
137                                       0.0, FALSE, 0.0, 0.0);
138
139         notice = rr_client_parse_notice (game->client, notice_s);
140         switch (notice->type) {
141         case RR_NOTICE_USER:
142         case RR_NOTICE_QUIT:
143         case RR_NOTICE_GAME:
144         case RR_NOTICE_DISPOSE:
145         case RR_NOTICE_MESSAGE:
146         case RR_NOTICE_GAMESTATE:
147         case RR_NOTICE_JOIN:
148         case RR_NOTICE_WATCH:
149         case RR_NOTICE_PART:
150         case RR_NOTICE_BID:
151         case RR_NOTICE_REVOKE:
152         case RR_NOTICE_TIMER:
153         case RR_NOTICE_ABANDON:
154         case RR_NOTICE_NOBID:
155         case RR_NOTICE_ACTIVE:
156         case RR_NOTICE_MOVE:
157         case RR_NOTICE_UNDO:
158         case RR_NOTICE_RESET:
159         case RR_NOTICE_SCORE:
160         case RR_NOTICE_ACTIVATE:
161             /* XXX: Need to actually handle many of these. */
162             fprintf (stderr, "Warning: Ignoring notice of type %d\n", notice->type);
163             break;
164         case RR_NOTICE_POSITION:
165             rr_board_position (board, notice->u.position.robot,
166                                notice->u.position.x, notice->u.position.y);
167             gtk_widget_queue_draw (GTK_WIDGET (game->window));
168             break;
169         case RR_NOTICE_TURN:
170             rr_board_set_goal_target (board, notice->u.target);
171             gtk_widget_queue_draw (GTK_WIDGET (game->window));
172             break;
173         }
174         free (notice);
175     }
176 }
177
178 static void
179 grr_game_entry_callback (GtkWidget *widget,
180                          grr_game_t *game)
181 {
182     rr_status_t status;
183     const gchar *entry_text;
184     char **response;
185     int i;
186
187     entry_text = gtk_entry_get_text (GTK_ENTRY (game->command_entry));
188
189     status = rr_client_request (game->client, entry_text, &response);
190     if (status) {
191         gtk_text_buffer_insert_at_cursor (game->message_buffer,
192                                           "ERROR: ", -1);
193         gtk_text_buffer_insert_at_cursor (game->message_buffer,
194                                           rr_status_str (status), -1);
195         gtk_text_buffer_insert_at_cursor (game->message_buffer,
196                                           "\n", -1);
197     } else {
198         for (i=0; response[i]; i++) {
199             gtk_text_buffer_insert_at_cursor (game->message_buffer,
200                                               response[i], -1);
201             gtk_text_buffer_insert_at_cursor (game->message_buffer,
202                                               " ", -1);
203         }
204         gtk_text_buffer_insert_at_cursor (game->message_buffer, "\n", -1);
205     }
206
207     gtk_entry_set_text (GTK_ENTRY (game->command_entry), "");
208
209     grr_game_read_notices (game);
210
211 /* XXX: Huh? Why is this triggering valgrind?
212     free (response);
213 */
214
215 }
216
217 static int
218 grr_game_start_gui (grr_game_t *game)
219 {
220     GtkWidget *board_frame;
221     GtkWidget *vpaned;
222     GtkWidget *sw;
223     GtkWidget *vbox;
224     GtkWidget *window;
225     GtkWidget *message_view;
226     GtkWidget *command_entry;
227
228     game->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
229     window = game->window;
230
231     gtk_window_set_title (GTK_WINDOW (window), "Ricochet Robot");
232     gtk_window_set_default_size (GTK_WINDOW (window), 512, 512);
233     
234     g_signal_connect (G_OBJECT (window), "destroy",
235                       G_CALLBACK (exit), NULL);
236     gtk_container_set_border_width (GTK_CONTAINER (window), 0);
237
238     vpaned = gtk_vpaned_new ();
239     gtk_container_set_border_width (GTK_CONTAINER (vpaned), 5);
240     gtk_container_add (GTK_CONTAINER (window), vpaned);
241     {
242         board_frame = gtk_aspect_frame_new (NULL, 0.5, 0.5, 1.0, FALSE);
243         gtk_paned_pack1 (GTK_PANED (vpaned), board_frame, TRUE, TRUE);
244         {
245             game->board_view = grr_board_view_new (game->board);
246             grr_board_view_set_client (GRR_BOARD_VIEW (game->board_view),
247                                        game->client);
248
249             gtk_container_add (GTK_CONTAINER (board_frame), game->board_view);
250             gtk_widget_show (game->board_view);
251         }
252         gtk_widget_show (board_frame);
253
254         vbox = gtk_vbox_new (FALSE, 1);
255         gtk_paned_pack2 (GTK_PANED (vpaned), vbox, FALSE, TRUE);
256         {
257             sw = gtk_scrolled_window_new (NULL, NULL);
258             gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
259                                             GTK_POLICY_NEVER,
260                                             GTK_POLICY_AUTOMATIC);
261             gtk_container_add (GTK_CONTAINER (vbox), sw);
262             gtk_widget_show (sw);
263
264             game->message_buffer = gtk_text_buffer_new (NULL);
265             game->message_view = gtk_text_view_new_with_buffer (game->message_buffer);
266             message_view = game->message_view;
267             gtk_text_view_set_editable (GTK_TEXT_VIEW (message_view), FALSE);
268             gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (message_view), FALSE);
269             gtk_container_add (GTK_CONTAINER (sw), message_view);
270             gtk_widget_show (message_view);
271
272             game->command_entry = gtk_entry_new ();
273             command_entry = game->command_entry;
274             gtk_container_add (GTK_CONTAINER (vbox), command_entry);
275             gtk_widget_show (command_entry);
276             g_signal_connect (G_OBJECT (command_entry), "activate",
277                               G_CALLBACK (grr_game_entry_callback),
278                               (gpointer) game);
279         }
280         gtk_widget_show (vbox);
281     }
282     gtk_widget_show (vpaned);
283
284     gtk_widget_show (window);
285     
286     grr_game_read_notices (game);
287
288     gtk_main ();
289     
290     return 0;
291 }