[Xfce4-commits] <xfce4-panel:master> Add hidden game.

Nick Schermer noreply at xfce.org
Tue Mar 23 21:40:01 CET 2010


Updating branch refs/heads/master
         to dbda8ee64f602a415ed1d8df6322de08dcbdb344 (commit)
       from 6268b05c44ffffa1dd3f2366b7e7af9972b79fe8 (commit)

commit dbda8ee64f602a415ed1d8df6322de08dcbdb344
Author: Nick Schermer <nick at xfce.org>
Date:   Tue Mar 23 20:38:25 2010 +0100

    Add hidden game.

 panel/Makefile.am         |    2 +
 panel/panel-dialogs.c     |   27 ++-
 panel/panel-tic-tac-toe.c |  658 +++++++++++++++++++++++++++++++++++++++++++++
 panel/panel-tic-tac-toe.h |   43 +++
 po/POTFILES.in            |    1 +
 5 files changed, 729 insertions(+), 2 deletions(-)

diff --git a/panel/Makefile.am b/panel/Makefile.am
index 5183c32..906217a 100644
--- a/panel/Makefile.am
+++ b/panel/Makefile.am
@@ -47,6 +47,8 @@ xfce4_panel_SOURCES = \
 	panel-plugin-external-46.h \
 	panel-preferences-dialog.c \
 	panel-preferences-dialog.h \
+	panel-tic-tac-toe.c \
+	panel-tic-tac-toe.h \
 	panel-window.c \
 	panel-window.h
 
diff --git a/panel/panel-dialogs.c b/panel/panel-dialogs.c
index b18603d..32f017f 100644
--- a/panel/panel-dialogs.c
+++ b/panel/panel-dialogs.c
@@ -33,6 +33,28 @@
 
 #include <panel/panel-dialogs.h>
 #include <panel/panel-application.h>
+#include <panel/panel-tic-tac-toe.h>
+
+
+
+static void
+panel_dialogs_show_about_email_hook (GtkAboutDialog *dialog,
+                                     const gchar    *uri,
+                                     gpointer        data)
+{
+  if (g_strcmp0 ("tictactoe at xfce.org", uri) == 0)
+    {
+      /* gtk needs to finish some stuff before the dialog can be closed */
+      exo_gtk_object_destroy_later (GTK_OBJECT (dialog));
+
+      /* open tic-tac-toe */
+      panel_tic_tac_toe_show ();
+    }
+  else
+    {
+      exo_gtk_url_about_dialog_hook (dialog, uri, data);
+    }
+}
 
 
 
@@ -43,12 +65,12 @@ panel_dialogs_show_about (void)
   {
     "Jasper Huijsmans <jasper at xfce.org>",
     "Nick Schermer <nick at xfce.org>",
+    "Tic-tac-toe <tictactoe at xfce.org>",
     NULL
   };
 
+  gtk_about_dialog_set_email_hook (panel_dialogs_show_about_email_hook, NULL, NULL);
 #if !GTK_CHECK_VERSION (2, 18, 0)
-  /* set exo hooks for urls and email */
-  gtk_about_dialog_set_email_hook (exo_gtk_url_about_dialog_hook, NULL, NULL);
   gtk_about_dialog_set_url_hook (exo_gtk_url_about_dialog_hook, NULL, NULL);
 #endif
 
@@ -64,6 +86,7 @@ panel_dialogs_show_about (void)
                          "website", "http://www.xfce.org/",
                          "logo-icon-name", PACKAGE_NAME,
                          NULL);
+
 }
 
 
diff --git a/panel/panel-tic-tac-toe.c b/panel/panel-tic-tac-toe.c
new file mode 100644
index 0000000..77d8493
--- /dev/null
+++ b/panel/panel-tic-tac-toe.c
@@ -0,0 +1,658 @@
+/*
+ * Copyright (C) 2010 Nick Schermer <nick at xfce.org>
+ *
+ * The game code has been taken (with adjustments) from the javascript
+ * game of Stephen Ostermiller: http://ostermiller.org/calc/tictactoe.html.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include <libxfce4ui/libxfce4ui.h>
+#include <libxfce4util/libxfce4util.h>
+
+#include <common/panel-private.h>
+#include <panel/panel-tic-tac-toe.h>
+
+
+
+static void panel_tic_tac_toe_response       (GtkDialog      *dialog,
+                                              gint            response_id);
+static void panel_tic_tac_toe_move           (PanelTicTacToe *dialog);
+static void panel_tic_tac_toe_button_clicked (GtkWidget      *button,
+                                              PanelTicTacToe *dialog);
+static void panel_tic_tac_toe_new_game       (PanelTicTacToe *dialog);
+
+
+
+#define cells_to_hex(c1,c2,c3,c4,c5,c6,c7,c8,c9)  (c1 << 0 | c2 << 1 | c3 << 2 | \
+                                                   c4 << 3 | c5 << 4 | c6 << 5 | \
+                                                   c7 << 6 | c8 << 7 | c9 << 8)
+#define cells_to_hex2(c1,c2,c3,c4,c5,c6,c7,c8,c9) (c1 << 0 | c2 << 2 | c3 << 4 | \
+                                                   c4 << 6 | c5 << 8 | c6 << 10 | \
+                                                   c7 << 12 | c8 << 14 | c9 << 16)
+#define winner_hex(winner,state)                  ((((winner) - 1) << 18) | (state))
+
+
+
+struct _PanelTicTacToeClass
+{
+  XfceTitledDialogClass __parent__;
+};
+
+struct _PanelTicTacToe
+{
+  XfceTitledDialog  __parent__;
+
+  GtkWidget *buttons[9];
+  GtkWidget *labels[9];
+  GtkWidget *level;
+};
+
+enum
+{
+  LEVEL_NOVICE,
+  LEVEL_INTERMEDIATE,
+  LEVEL_EXPERIENCED,
+  LEVEL_EXPERT
+};
+
+enum
+{
+  ONE      = 1,
+  PLAYER_O = 2,
+  PLAYER_X = 3,
+  TIE      = 4
+};
+
+
+
+G_DEFINE_TYPE (PanelTicTacToe, panel_tic_tac_toe, XFCE_TYPE_TITLED_DIALOG)
+
+
+
+static void
+panel_tic_tac_toe_class_init (PanelTicTacToeClass *klass)
+{
+  GtkDialogClass *gtkdialog_class;
+
+  gtkdialog_class = GTK_DIALOG_CLASS (klass);
+  gtkdialog_class->response = panel_tic_tac_toe_response;
+}
+
+
+
+static void
+panel_tic_tac_toe_init (PanelTicTacToe *dialog)
+{
+  GtkWidget *button;
+  GtkWidget *table;
+  GtkWidget *separator;
+  guint      i;
+  GtkWidget *label;
+  guint      row, col;
+  GtkWidget *align;
+  GtkWidget *vbox;
+  GtkWidget *combo;
+  GtkWidget *hbox;
+
+  gtk_window_set_title (GTK_WINDOW (dialog), "Tic-tac-toe");
+  gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+  gtk_window_set_icon_name (GTK_WINDOW (dialog), "applications-games");
+  gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+
+  button = xfce_gtk_button_new_mixed (GTK_STOCK_NEW, _("_New Game"));
+  gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, GTK_RESPONSE_ACCEPT);
+  gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
+
+  vbox = gtk_vbox_new (FALSE, 6);
+  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), vbox, TRUE, TRUE, 0);
+  gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
+
+  hbox = gtk_hbox_new (FALSE, 12);
+  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+
+  label = gtk_label_new_with_mnemonic (_("_Level:"));
+  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+  dialog->level = combo = gtk_combo_box_new_text ();
+  gtk_box_pack_start (GTK_BOX (hbox), combo, FALSE, FALSE, 0);
+  gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
+  gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("Novice"));
+  gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("Intermidiate"));
+  gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("Experienced"));
+  gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("Expert"));
+  gtk_combo_box_set_active (GTK_COMBO_BOX (combo), LEVEL_EXPERIENCED);
+
+  align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
+  gtk_box_pack_start (GTK_BOX (vbox), align, TRUE, TRUE, 0);
+
+  table = gtk_table_new (5, 5, FALSE);
+  gtk_table_set_col_spacings (GTK_TABLE (table), 1);
+  gtk_table_set_row_spacings (GTK_TABLE (table), 1);
+  gtk_container_add (GTK_CONTAINER (align), table);
+
+  separator = gtk_hseparator_new ();
+  gtk_table_attach (GTK_TABLE (table), separator, 0, 5, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
+  separator = gtk_hseparator_new ();
+  gtk_table_attach (GTK_TABLE (table), separator, 0, 5, 3, 4, GTK_FILL, GTK_FILL, 0, 0);
+  separator = gtk_vseparator_new ();
+  gtk_table_attach (GTK_TABLE (table), separator, 1, 2, 0, 5, GTK_FILL, GTK_FILL, 0, 0);
+  separator = gtk_vseparator_new ();
+  gtk_table_attach (GTK_TABLE (table), separator, 3, 4, 0, 5, GTK_FILL, GTK_FILL, 0, 0);
+
+  for (i = 0; i < 9; i++)
+    {
+      button = dialog->buttons[i] = gtk_button_new ();
+      gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
+      gtk_widget_set_size_request (button, 70, 70);
+      gtk_widget_set_can_focus (button, FALSE);
+      g_signal_connect (G_OBJECT (button), "clicked",
+          G_CALLBACK (panel_tic_tac_toe_button_clicked), dialog);
+
+      label = dialog->labels[i] = gtk_label_new ("");
+      gtk_container_add (GTK_CONTAINER (button), label);
+
+      row = (i / 3) * 2;
+      col = (i % 3) * 2;
+
+      gtk_table_attach (GTK_TABLE (table), button,
+                        col, col + 1,
+                        row, row + 1,
+                        GTK_EXPAND | GTK_FILL,
+                        GTK_EXPAND | GTK_FILL,
+                        0, 0);
+    }
+
+  /* set label attributes */
+  panel_tic_tac_toe_new_game (dialog);
+}
+
+
+
+static void
+panel_tic_tac_toe_response (GtkDialog *gtk_dialog,
+                            gint       response_id)
+{
+  panel_return_if_fail (PANEL_IS_TIC_TAC_TOE (gtk_dialog));
+
+  if (response_id == GTK_RESPONSE_ACCEPT)
+    {
+      /* new game */
+      panel_tic_tac_toe_new_game (PANEL_TIC_TAC_TOE (gtk_dialog));
+    }
+  else
+    {
+      gtk_widget_destroy (GTK_WIDGET (gtk_dialog));
+    }
+}
+
+
+
+static gint
+panel_tic_tac_toe_has_winner (gint state)
+{
+  guint i;
+  gint  player_x, player_o, tie;
+  gint  matches[] =
+  {
+    /* horizontal */
+    cells_to_hex2 (ONE, ONE, ONE, 0, 0, 0, 0, 0, 0),
+    cells_to_hex2 (0, 0, 0, ONE, ONE, ONE, 0, 0, 0),
+    cells_to_hex2 (0, 0, 0, 0, 0, 0, ONE, ONE, ONE),
+
+    /* vertical */
+    cells_to_hex2 (ONE, 0, 0, ONE, 0, 0, ONE, 0, 0),
+    cells_to_hex2 (0, ONE, 0, 0, ONE, 0, 0, ONE, 0),
+    cells_to_hex2 (0, 0, ONE, 0, 0, ONE, 0, 0, ONE),
+
+    /* diagonal */
+    cells_to_hex2 (ONE, 0, 0, 0, ONE, 0, 0, 0, ONE),
+    cells_to_hex2 (0, 0, ONE, 0, ONE, 0, ONE, 0, 0),
+  };
+
+  for (i = 0; i < G_N_ELEMENTS (matches); i++)
+    {
+      /* x wins */
+      player_x = matches[i] * PLAYER_X;
+      if ((state & player_x) == player_x)
+        return winner_hex (PLAYER_X, player_x);
+
+      /* o wins */
+      player_o = matches[i] * PLAYER_O;
+      if ((state & player_x) == player_o)
+        return winner_hex (PLAYER_O, player_o);
+    }
+
+  /* tie */
+  tie = cells_to_hex2 (PLAYER_O, PLAYER_O, PLAYER_O,
+                       PLAYER_O, PLAYER_O, PLAYER_O,
+                       PLAYER_O, PLAYER_O, PLAYER_O);
+  if ((state & tie) == tie)
+    return winner_hex (TIE, 0);
+
+  /* no winner or tie */
+  return 0;
+}
+
+
+
+static gint
+panel_tic_tac_toe_best_opening (gint state,
+                                gint possible_initial_moves)
+{
+  gint mask;
+
+  /* no moves yet, return the valid initial moves */
+  if (state == 0)
+    return possible_initial_moves;
+
+  mask = state & cells_to_hex2 (PLAYER_O, PLAYER_O, PLAYER_O,
+                                PLAYER_O, PLAYER_O, PLAYER_O,
+                                PLAYER_O, PLAYER_O, PLAYER_O);
+
+  /* user took the center, pick a corner */
+  if (mask == cells_to_hex2 (0, 0, 0, 0, PLAYER_O, 0, 0, 0, 0))
+    return cells_to_hex (ONE, 0, ONE, 0, 0, 0, ONE, 0, ONE);
+
+  /* user took a corner, pick the center */
+  if (mask == cells_to_hex2 (PLAYER_O, 0, 0, 0, 0, 0, 0, 0, 0)
+      || mask == cells_to_hex2 (0, 0, PLAYER_O, 0, 0, 0, 0, 0, 0)
+      || mask == cells_to_hex2 (0, 0, 0, 0, 0, 0, PLAYER_O, 0, 0)
+      || mask == cells_to_hex2 (0, 0, 0, 0, 0, 0, 0, 0, PLAYER_O))
+    return cells_to_hex (0, 0, 0, 0, ONE, 0, 0, 0, 0);
+
+  /* user took an edge, pick something in the same diagonal */
+  if (mask == cells_to_hex2 (0, PLAYER_O, 0, 0, 0, 0, 0, 0, 0))
+    return cells_to_hex (ONE, 0, ONE, 0, ONE, 0, 0, ONE, 0);
+  if (mask == cells_to_hex2 (0, 0, 0, PLAYER_O, 0, 0, 0, 0, 0))
+    return cells_to_hex (ONE, 0, 0, 0, ONE, ONE, ONE, 0, 0);
+  if (mask == cells_to_hex2 (0, 0, 0, 0, 0, PLAYER_O, 0, 0, 0))
+    return cells_to_hex (0, 0, ONE, ONE, ONE, 0, 0, 0, ONE);
+  if (mask == cells_to_hex2 (0, 0, 0, 0, 0, 0, 0, PLAYER_O, 0))
+    return cells_to_hex (0, ONE, 0, 0, ONE, 0, ONE, 0, ONE);
+
+  /* no best opening move possible */
+  return 0;
+}
+
+
+
+static gint
+panel_tic_tac_toe_get_random_move (gint moves)
+{
+  gint i;
+  gint n_moves;
+  gint seed;
+
+  /* count number of moves in the state */
+  for (i = 0, n_moves = 0; i < 9; i++)
+    if ((moves & (1 << i)) != 0)
+      n_moves++;
+
+  if (n_moves > 0)
+    {
+      /* return one random move from the state */
+      seed = g_random_int_range (0, n_moves);
+      for (i = 0, n_moves = 0; i < 9; i++)
+        {
+          if ((moves & (1 << i)) != 0
+              && n_moves++ == seed)
+            return i;
+        }
+
+      panel_assert_not_reached ();
+    }
+
+  /* no move possible */
+  return -1;
+}
+
+
+
+static gint
+panel_tic_tac_toe_get_legal_moves (gint state)
+{
+  gint i, moves = 0;
+
+  for (i = 0; i < 9; i++)
+    if ((state & (1 << (i * 2 + 1))) == 0)
+      moves |= 1 << i;
+
+  return moves;
+}
+
+
+
+static gint
+panel_tic_tac_toe_get_winner_move (gint state,
+                                   gint player)
+{
+  gint i;
+
+  for (i = 0; i < 9; i++)
+    if ((state & (1 << (i * 2 + 1))) == 0)
+      if (panel_tic_tac_toe_has_winner (state | (player << (i * 2))) != 0)
+        return 1 << i;
+
+  return 0;
+}
+
+
+
+static gint
+panel_tic_tac_toe_get_move_rate (gint state,
+                                 gint move,
+                                 gint move_for,
+                                 gint next_turn,
+                                 gint limit,
+                                 gint depth)
+{
+  gint new_state;
+  gint winner;
+  gint rate;
+  gint legal_moves, i;
+  gint value;
+
+  new_state = state | (next_turn << (move * 2));
+
+  /* check if this new state has a winner or tie */
+  winner = panel_tic_tac_toe_has_winner (new_state);
+  if (winner == winner_hex (TIE, 0))
+    return 0;
+  if (winner != 0)
+    {
+      if (move_for == next_turn)
+        return 10 - depth;
+      else
+        return depth - 10;
+    }
+
+  rate = move_for == next_turn ? 999 : -999;
+  if (depth == limit)
+    return rate;
+
+  legal_moves = panel_tic_tac_toe_get_legal_moves (new_state);
+  for (i = 0; i < 9; i++)
+    {
+      if ((legal_moves & (1 << i)) != 0)
+        {
+          value = panel_tic_tac_toe_get_move_rate (new_state, i, move_for,
+                                                   next_turn == PLAYER_O ? PLAYER_X : PLAYER_O,
+                                                   10 - ABS (rate), depth + 1);
+          if (ABS (value) != 999)
+            {
+              if ((move_for == next_turn && value < rate)
+                  || (move_for != next_turn && value > rate))
+                rate = value;
+            }
+        }
+    }
+
+  return rate;
+}
+
+
+
+static gint
+panel_tic_tac_toe_get_move (gint state,
+                            gint player,
+                            gint level)
+{
+  gint winner;
+  gint moves, legal_moves;
+  gint first_moves;
+  gint rate, value;
+  gint i;
+  gint move = -1;
+
+  winner = panel_tic_tac_toe_has_winner (state);
+  if (winner == 0)
+    {
+      legal_moves = panel_tic_tac_toe_get_legal_moves (state);
+
+      switch (level)
+        {
+        case LEVEL_EXPERT:
+          /* just take a random position on the first move */
+          first_moves = cells_to_hex (ONE, ONE, ONE, ONE, ONE, ONE, ONE, ONE, ONE);
+          moves = panel_tic_tac_toe_best_opening (state, first_moves);
+          if (moves != 0)
+            break;
+
+          /* find the moves with the best rate */
+          rate = -999;
+          for (i = 0; i < 9; i++)
+            {
+               if ((legal_moves & (1 << i)) == 0)
+                 continue;
+
+               value = panel_tic_tac_toe_get_move_rate (state, i, player, player, 15, 1);
+               if (value > rate)
+                 {
+                   /* found a better game, reset moves */
+                   rate = value;
+                   moves = 0;
+                 }
+
+               /* add the moves with the current rating */
+               if (rate == value)
+                 moves |= (1 << i);
+
+            }
+          break;
+
+        case LEVEL_EXPERIENCED:
+          /* take a corner on the first move */
+          first_moves = cells_to_hex (ONE, 0, ONE, 0, 0, 0, ONE, 0, ONE);
+          moves = panel_tic_tac_toe_best_opening (state, first_moves);
+          if (moves != 0)
+            break;
+
+        case LEVEL_INTERMEDIATE:
+          /* try to find a winning move */
+          moves = panel_tic_tac_toe_get_winner_move (state, PLAYER_X);
+          if (moves != 0)
+            break;
+
+          /* try to find a blocking move */
+          moves = panel_tic_tac_toe_get_winner_move (state, PLAYER_O);
+          if (moves != 0)
+            break;
+
+        case LEVEL_NOVICE:
+          moves = legal_moves;
+          break;
+        }
+
+      move = panel_tic_tac_toe_get_random_move (moves);
+    }
+
+  return move;
+}
+
+
+
+static gint
+panel_tic_tac_toe_get_state (PanelTicTacToe *dialog)
+{
+  gint         state = 0;
+  gint         i;
+  const gchar *text;
+  gint         value;
+
+  panel_return_val_if_fail (PANEL_IS_TIC_TAC_TOE (dialog), 0);
+
+  for (i = 0; i < 9; i++)
+    {
+      text = gtk_label_get_text (GTK_LABEL (dialog->labels[i]));
+
+      if (text != NULL && *text == 'X')
+        value = PLAYER_X;
+      else if (text != NULL && *text == 'O')
+        value = PLAYER_O;
+      else
+        continue;
+
+      state |= value << (i * 2);
+    }
+
+  return state;
+}
+
+
+
+static void
+panel_tic_tac_toe_move (PanelTicTacToe *dialog)
+{
+  gint move;
+  gint state;
+  gint level;
+
+  panel_return_if_fail (PANEL_IS_TIC_TAC_TOE (dialog));
+
+  state = panel_tic_tac_toe_get_state (dialog);
+  level = gtk_combo_box_get_active (GTK_COMBO_BOX (dialog->level));
+  move = panel_tic_tac_toe_get_move (state, PLAYER_X, level);
+  if (move != -1)
+    {
+      gtk_widget_set_sensitive (dialog->buttons[move], FALSE);
+      gtk_label_set_text (GTK_LABEL (dialog->labels[move]), "X");
+    }
+
+
+}
+
+
+
+static void
+panel_tic_tac_toe_highlight_winner (PanelTicTacToe *dialog,
+                                    gint            winner)
+{
+  PangoAttribute *attr;
+  PangoAttrList  *attrs;
+  gint            i;
+  gint            tie;
+
+  panel_return_if_fail (PANEL_IS_TIC_TAC_TOE (dialog));
+
+  tie = winner_hex (TIE, 0);
+  if ((winner & tie) == winner_hex (PLAYER_X, 0))
+    {
+      attr = pango_attr_foreground_new (0xffff, 0, 0);
+    }
+  else if ((winner & tie) == winner_hex (PLAYER_O, 0))
+    {
+      attr = pango_attr_foreground_new (0, 0, 0xffff);
+    }
+  else
+    {
+      /* grey out all the cells */
+      attr = pango_attr_foreground_new (0xcccc, 0xcccc, 0xcccc);
+      winner |= cells_to_hex2 (PLAYER_O, PLAYER_O, PLAYER_O,
+                               PLAYER_O, PLAYER_O, PLAYER_O,
+                               PLAYER_O, PLAYER_O, PLAYER_O);
+    }
+
+  for (i = 0; i < 9; i++)
+    {
+      gtk_widget_set_sensitive (dialog->buttons[i], FALSE);
+
+      if ((winner & (1 << (i * 2 + 1))) != 0)
+        {
+          attrs = gtk_label_get_attributes (GTK_LABEL (dialog->labels[i]));
+          pango_attr_list_insert (attrs, pango_attribute_copy (attr));
+          gtk_label_set_attributes (GTK_LABEL (dialog->labels[i]), attrs);
+        }
+    }
+
+  pango_attribute_destroy (attr);
+}
+
+
+
+static void
+panel_tic_tac_toe_button_clicked (GtkWidget      *button,
+                                  PanelTicTacToe *dialog)
+{
+  GtkWidget *label;
+  gint       state;
+  gint       winner;
+
+  panel_return_if_fail (PANEL_IS_TIC_TAC_TOE (dialog));
+
+  label = gtk_bin_get_child (GTK_BIN (button));
+  gtk_widget_set_sensitive (button, FALSE);
+  gtk_label_set_text (GTK_LABEL (label), "O");
+
+  panel_tic_tac_toe_move (dialog);
+
+  state = panel_tic_tac_toe_get_state (dialog);
+  winner = panel_tic_tac_toe_has_winner (state);
+  if (winner != 0)
+    panel_tic_tac_toe_highlight_winner (dialog, winner);
+}
+
+
+
+static void
+panel_tic_tac_toe_new_game (PanelTicTacToe *dialog)
+{
+  PangoAttrList  *attrs, *attrs_dup;
+  PangoAttribute *attr;
+  gint            i;
+
+  attrs = pango_attr_list_new ();
+  attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
+  pango_attr_list_insert (attrs, attr);
+  attr = pango_attr_size_new (36 * PANGO_SCALE);
+  pango_attr_list_insert (attrs, attr);
+  attr = pango_attr_foreground_new (0, 0, 0);
+  pango_attr_list_insert (attrs, attr);
+
+  for (i = 0; i < 9; i++)
+    {
+      gtk_label_set_text (GTK_LABEL (dialog->labels[i]), "");
+      gtk_widget_set_sensitive (dialog->buttons[i], TRUE);
+
+      attrs_dup = pango_attr_list_copy (attrs);
+      gtk_label_set_attributes (GTK_LABEL (dialog->labels[i]), attrs_dup);
+      pango_attr_list_unref (attrs_dup);
+    }
+
+  pango_attr_list_unref (attrs);
+
+  /* 50/50 the panel will start the game */
+  if (g_random_int_range (0, 2) == 0)
+    panel_tic_tac_toe_move (dialog);
+}
+
+
+
+void
+panel_tic_tac_toe_show (void)
+{
+  GtkWidget *dialog;
+
+  dialog = g_object_new (PANEL_TYPE_TIC_TAC_TOE, NULL);
+  gtk_widget_show_all (dialog);
+}
diff --git a/panel/panel-tic-tac-toe.h b/panel/panel-tic-tac-toe.h
new file mode 100644
index 0000000..b648e01
--- /dev/null
+++ b/panel/panel-tic-tac-toe.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2010 Nick Schermer <nick at xfce.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __PANEL_TIC_TAC_TOE_H__
+#define __PANEL_TIC_TAC_TOE_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+typedef struct _PanelTicTacToeClass PanelTicTacToeClass;
+typedef struct _PanelTicTacToe      PanelTicTacToe;
+
+#define PANEL_TYPE_TIC_TAC_TOE            (panel_tic_tac_toe_get_type ())
+#define PANEL_TIC_TAC_TOE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), PANEL_TYPE_TIC_TAC_TOE, PanelTicTacToe))
+#define PANEL_TIC_TAC_TOE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), PANEL_TYPE_TIC_TAC_TOE, PanelTicTacToeClass))
+#define PANEL_IS_TIC_TAC_TOE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PANEL_TYPE_TIC_TAC_TOE))
+#define PANEL_IS_TIC_TAC_TOE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PANEL_TYPE_TIC_TAC_TOE))
+#define PANEL_TIC_TAC_TOE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), PANEL_TYPE_TIC_TAC_TOE, PanelTicTacToeClass))
+
+GType      panel_tic_tac_toe_get_type (void) G_GNUC_CONST;
+
+void       panel_tic_tac_toe_show     (void);
+
+G_END_DECLS
+
+#endif /* !__PANEL_TIC_TAC_TOE_H__ */
+
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 14c6d26..10029ee 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -24,6 +24,7 @@ panel/panel-plugin-external.c
 panel/panel-plugin-external-46.c
 panel/panel-preferences-dialog.c
 panel/panel-preferences-dialog.glade
+panel/panel-tic-tac-toe.c
 panel/panel-window.c
 
 wrapper/main.c



More information about the Xfce4-commits mailing list