1. /**
  2. * Copyright (C) 2007 by Marcelo Jorge Vieira (metal) <metal@alucinados.com>
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2.1 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this library; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  17. *
  18. * Public License can be found at http://www.gnu.org/copyleft/gpl.html
  19. *
  20. *
  21. * @author Thadeu Cascardo <cascardo@minaslivre.org>
  22. * @author Marcelo Jorge Vieira (metal) <metal@alucinados.com>
  23. *
  24. */
  25.  
  26. #include <gtk/gtk.h>
  27. #include "velha.h"
  28.  
  29. GdkPixbuf *pixbuf_O;
  30. GdkPixbuf *pixbuf_X;
  31. GtkWidget *statusbar;
  32.  
  33. GtkListStore* store;
  34.  
  35. GString *strbuffer;
  36. GIOChannel *channel;
  37.  
  38. gboolean started;
  39. gboolean played;
  40. gboolean listed;
  41.  
  42. gint game;
  43. gint lastpos;
  44.  
  45. GtkWidget *velha[9];
  46.  
  47. void
  48. button_pressed (GtkButton *button, gpointer data)
  49. {
  50. gint position;
  51. char *str;
  52. GString *str2;
  53.  
  54. position = GPOINTER_TO_INT (data);
  55. str = g_strdup_printf ("Pressed button %d", position);
  56. gtk_statusbar_push (GTK_STATUSBAR (statusbar),
  57. gtk_statusbar_get_context_id (GTK_STATUSBAR (statusbar), str), str);
  58. g_free (str);
  59. str2 = g_string_sized_new (BUFSIZ);
  60. g_string_printf (str2, "PLAY %d\r\n", position);
  61. write (g_io_channel_unix_get_fd (channel), str2->str, str2->len);
  62. g_string_free (str2, TRUE);
  63. lastpos = position;
  64. played = 1;
  65. }
  66.  
  67. void
  68. start_clicked (GtkButton *button, gpointer data)
  69. {
  70. write (g_io_channel_unix_get_fd (channel), "START\r\n", 7);
  71. started = 1;
  72. }
  73.  
  74. void
  75. join_clicked (GtkButton *button, gpointer data)
  76. {
  77. GtkTreeIter iter;
  78. GString *str;
  79.  
  80. if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (data), &iter))
  81. return;
  82. gtk_tree_model_get (gtk_combo_box_get_model (GTK_COMBO_BOX (data)), &iter, 1, &game, -1);
  83. str = g_string_sized_new (BUFSIZ);
  84. g_string_printf (str, "JOIN %d\r\n", game);
  85. write (g_io_channel_unix_get_fd (channel), str->str, str->len);
  86. g_string_free (str, TRUE);
  87. }
  88.  
  89. GtkWidget *
  90. my_combo_new ()
  91. {
  92. GtkWidget *combobox;
  93. GtkCellRenderer* renderer;
  94.  
  95. store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
  96. combobox = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store));
  97. renderer = gtk_cell_renderer_text_new ();
  98. gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combobox), renderer, TRUE);
  99. gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combobox), renderer, "text", 0, NULL);
  100.  
  101. return combobox;
  102.  
  103. }
  104.  
  105. void
  106. ui_init ()
  107. {
  108. GtkWidget *window;
  109. GtkWidget *vbox;
  110. GtkWidget *hbox;
  111. GtkWidget *button;
  112. GtkWidget *entry;
  113.  
  114. int i;
  115. int j;
  116.  
  117. window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  118. gtk_window_set_title (GTK_WINDOW (window), "velha");
  119. gtk_container_set_border_width (GTK_CONTAINER (window), 10);
  120. vbox = gtk_vbox_new (FALSE, 5);
  121. gtk_container_add (GTK_CONTAINER (window), vbox);
  122. pixbuf_O = gdk_pixbuf_new_from_file_at_size ("velha_o.png", 100, 100, NULL);
  123. pixbuf_X = gdk_pixbuf_new_from_file_at_size ("velha_x.png", 100, 100, NULL);
  124.  
  125. hbox = gtk_hbox_new (TRUE, 5);
  126. gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 5);
  127.  
  128. button = gtk_button_new_with_label ("Start new game");
  129. gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 5);
  130. g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (start_clicked), NULL);
  131.  
  132. entry = my_combo_new ();
  133. gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
  134.  
  135. button = gtk_button_new_with_label ("Join existing game");
  136. gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
  137. g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (join_clicked), entry);
  138.  
  139. for (i = 0; i < 3; i++)
  140. {
  141. hbox = gtk_hbox_new (TRUE, 5);
  142. gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 5);
  143. for (j = 0; j < 3; j++)
  144. {
  145. velha[INDEX(i,j)] = gtk_button_new ();
  146. gtk_container_add (GTK_CONTAINER (hbox), velha[INDEX(i,j)]);
  147. gtk_widget_set_usize (velha[INDEX(i,j)], 120, 120);
  148. g_signal_connect (G_OBJECT (velha[INDEX(i,j)]), "clicked", G_CALLBACK (button_pressed), GINT_TO_POINTER (INDEX(i,j)));
  149. }
  150. }
  151.  
  152. statusbar = gtk_statusbar_new ();
  153. gtk_box_pack_start (GTK_BOX (vbox), statusbar, FALSE, FALSE, 0);
  154. g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (gtk_main_quit), NULL);
  155. gtk_widget_show_all (window);
  156. }
  157.  
  158. void
  159. myfar (char *buffer, int len)
  160. {
  161. if (started)
  162. {
  163. /* Waits for game number */
  164. char *end;
  165. char *str;
  166.  
  167. buffer[len - 1] = 0;
  168. errno = 0;
  169. game = strtol (buffer, &end, 0);
  170. if (end == buffer || errno != 0 || game < 0 || game > G_MAXINT)
  171. {
  172. str = g_strdup_printf ("Error starting game");
  173. gtk_statusbar_push (GTK_STATUSBAR (statusbar),
  174. gtk_statusbar_get_context_id (GTK_STATUSBAR (statusbar), str), str);
  175. g_free (str);
  176. return;
  177. }
  178. str = g_strdup_printf ("Started game %d", game);
  179. gtk_statusbar_push (GTK_STATUSBAR (statusbar),
  180. gtk_statusbar_get_context_id (GTK_STATUSBAR (statusbar), str), str);
  181. g_free (str);
  182. started = 0;
  183. }
  184. else if (played)
  185. {
  186. char *end;
  187. char *str;
  188. int status;
  189.  
  190. buffer[len - 1] = 0;
  191. errno = 0;
  192. status = strtol (buffer, &end, 0);
  193. if (end == buffer || errno != 0 || status < 0 || status > G_MAXINT)
  194. {
  195. str = g_strdup_printf ("Error: broken server");
  196. gtk_statusbar_push (GTK_STATUSBAR (statusbar),
  197. gtk_statusbar_get_context_id (GTK_STATUSBAR (statusbar), str), str);
  198. g_free (str);
  199. return;
  200. }
  201. if (status != 200)
  202. {
  203. str = g_strdup_printf ("Error playing: %s", end);
  204. gtk_statusbar_push (GTK_STATUSBAR (statusbar),
  205. gtk_statusbar_get_context_id (GTK_STATUSBAR (statusbar), str), str);
  206. g_free (str);
  207. }
  208. else
  209. {
  210. GtkWidget *image;
  211. str = g_strdup_printf ("Played position: %d", lastpos);
  212. gtk_statusbar_push (GTK_STATUSBAR (statusbar),
  213. gtk_statusbar_get_context_id (GTK_STATUSBAR (statusbar), str), str);
  214. g_free (str);
  215. image = gtk_image_new_from_pixbuf (pixbuf_O);
  216. gtk_button_set_image (GTK_BUTTON (velha[lastpos]), image);
  217. }
  218. played = 0;
  219. }
  220. else if (g_ascii_strncasecmp (buffer, "PLAY", 4) == 0)
  221. {
  222. /* Opponent has played */
  223. char *p;
  224. char *end;
  225. char *str;
  226. int position;
  227.  
  228. buffer[len - 1] = 0;
  229. p = buffer + sizeof ("PLAY");
  230. errno = 0;
  231. position = strtol (p, &end, 0);
  232. if (end == p || errno != 0 || position < 0 || position > 8)
  233. {
  234. str = g_strdup_printf ("Error: broken server");
  235. gtk_statusbar_push (GTK_STATUSBAR (statusbar),
  236. gtk_statusbar_get_context_id (GTK_STATUSBAR (statusbar), str), str);
  237. g_free (str);
  238. return;
  239. }
  240. else
  241. {
  242. GtkWidget *image;
  243.  
  244. str = g_strdup_printf ("Opponent played position: %d", position);
  245. gtk_statusbar_push (GTK_STATUSBAR (statusbar),
  246. gtk_statusbar_get_context_id (GTK_STATUSBAR (statusbar), str), str);
  247. g_free (str);
  248. image = gtk_image_new_from_pixbuf (pixbuf_X);
  249. gtk_button_set_image (GTK_BUTTON (velha[position]), image);
  250. }
  251. }
  252. else if (listed && g_ascii_strncasecmp (buffer, "END", 3) == 0)
  253. {
  254. listed = 0;
  255. }
  256. else if (listed && g_ascii_strncasecmp (buffer, "START", 5) == 0)
  257. {
  258. /* Who is responsible for this stupid protocol? Do nothing! */
  259. }
  260. else if (listed)
  261. {
  262. char *end;
  263. char *str;
  264. gint mygame;
  265.  
  266. buffer[len - 1] = 0;
  267. errno = 0;
  268. mygame = strtol (buffer, &end, 0);
  269. if (end == buffer || errno != 0 || mygame < 0 || mygame > G_MAXINT)
  270. {
  271. str = g_strdup_printf ("Error: broken server");
  272. gtk_statusbar_push (GTK_STATUSBAR (statusbar),
  273. gtk_statusbar_get_context_id (GTK_STATUSBAR (statusbar), str), str);
  274. g_free (str);
  275. return;
  276. }
  277. else
  278. {
  279. GtkTreeIter iter;
  280.  
  281. str = g_strdup_printf ("Seen game: %d", mygame);
  282. gtk_statusbar_push (GTK_STATUSBAR (statusbar),
  283. gtk_statusbar_get_context_id (GTK_STATUSBAR (statusbar), str), str);
  284. g_free (str);
  285. str = g_strdup_printf ("%d", mygame);
  286. gtk_list_store_prepend (store, &iter);
  287. gtk_list_store_set (store, &iter, 0, str, 1, mygame, -1);
  288. }
  289. }
  290. else if (g_ascii_strncasecmp (buffer, "200 WIN", 7) == 0)
  291. {
  292. char *str;
  293.  
  294. str = g_strdup_printf ("You win!");
  295. gtk_statusbar_push (GTK_STATUSBAR (statusbar),
  296. gtk_statusbar_get_context_id (GTK_STATUSBAR (statusbar), str), str);
  297. g_free (str);
  298. }
  299. else if (g_ascii_strncasecmp (buffer, "200 LOOSE", 9) == 0)
  300. {
  301. char *str;
  302.  
  303. str = g_strdup_printf ("You loose!");
  304. gtk_statusbar_push (GTK_STATUSBAR (statusbar),
  305. gtk_statusbar_get_context_id (GTK_STATUSBAR (statusbar), str), str);
  306. g_free (str);
  307. }
  308. else if (g_ascii_strncasecmp (buffer, "403 GAME", 8) == 0)
  309. {
  310. char *str;
  311.  
  312. str = g_strdup_printf ("Game already started! Go away!");
  313. gtk_statusbar_push (GTK_STATUSBAR (statusbar),
  314. gtk_statusbar_get_context_id (GTK_STATUSBAR (statusbar), str), str);
  315. g_free (str);
  316. }
  317. else if (g_ascii_strncasecmp (buffer, "200 TIE", 7) == 0)
  318. {
  319. char *str;
  320.  
  321. str = g_strdup_printf ("Game tie!");
  322. gtk_statusbar_push (GTK_STATUSBAR (statusbar),
  323. gtk_statusbar_get_context_id (GTK_STATUSBAR (statusbar), str), str);
  324. g_free (str);
  325. }
  326. }
  327.  
  328. gboolean
  329. myboo ()
  330. {
  331. int n;
  332. char *p;
  333. char *buffer;
  334.  
  335. for (n = 0, p = strbuffer->str; n < strbuffer->len; n++, p++)
  336. {
  337. if (*p == '\n' || (*p == '\r' && ++n < strbuffer->len && *(++p) == '\n'))
  338. break;
  339. }
  340. if (n == strbuffer->len)
  341. {
  342. //g_debug ("Time to learn how to count, cascardo.");
  343. return FALSE;
  344. }
  345. buffer = g_strndup (strbuffer->str, n + 1);
  346. g_string_erase (strbuffer, 0, n + 1);
  347. //g_debug ("Command %s received", buffer);
  348. myfar (buffer, n + 1);
  349. g_free (buffer);
  350. return TRUE;
  351. }
  352.  
  353. gboolean
  354. myread (GIOChannel *channel, GIOCondition cond, gpointer data)
  355. {
  356. int fd;
  357. char buffer[BUFSIZ];
  358. int r;
  359.  
  360. //g_debug ("New data");
  361. fd = g_io_channel_unix_get_fd (channel);
  362. r = read (fd, buffer, BUFSIZ);
  363. if ((r < 0 && errno != EAGAIN) || r == 0)
  364. {
  365. g_debug ("Error or finished connection.");
  366. g_io_channel_unref (channel);
  367. return FALSE;
  368. }
  369. g_string_append_len (strbuffer, buffer, r);
  370. while (myboo ());
  371. return TRUE;
  372. }
  373.  
  374. void
  375. net_init ()
  376. {
  377. int fd;
  378. struct sockaddr_in saddr;
  379.  
  380. fd = socket (PF_INET, SOCK_STREAM, 0);
  381. saddr.sin_family = AF_INET;
  382. saddr.sin_port = htons (5555);
  383. saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
  384. connect (fd, (struct sockaddr*) &saddr, sizeof (struct sockaddr_in));
  385. channel = g_io_channel_unix_new (fd);
  386. g_io_channel_set_close_on_unref (channel, TRUE);
  387. g_io_channel_set_flags (channel, g_io_channel_get_flags (channel) | G_IO_FLAG_NONBLOCK, NULL);
  388. g_io_add_watch (channel, G_IO_IN, myread, NULL);
  389. strbuffer = g_string_sized_new (BUFSIZ);
  390. write (fd, "LIST\r\n", 6);
  391. listed = 1;
  392. }
  393.  
  394. int
  395. main (int argc, char **argv)
  396. {
  397. gtk_init (&argc, &argv);
  398.  
  399. ui_init ();
  400. net_init ();
  401.  
  402. gtk_main ();
  403.  
  404. return 0;
  405. }
  406.