[five-or-more] Split five-or-more.c The current code existing in five-or-more.c has been split into:



commit 7294fa2d3e23fb2d1ab2eddf5a940128187239fc
Author: Karuna Grewal <karunagrewal98 gmail com>
Date:   Sun Mar 18 18:28:21 2018 +0530

    Split five-or-more.c The current code existing in five-or-more.c has been split into:
    
    * five-or-more-app.c : Here all  the callbacks to the application are connected,
      followed by the general setting related to the application like background
      color etc. are moved to this file
    
    * game-area.c: Drawing area related code ,say, binding signals to callbacks,
      or rendering the graphics, controlling the animation are handled here.
    
    * balls-preview.c: This has the necessary functions for previewing.
    
    Getters are used to access the static variables used across the appliaction
    which weren't currently required since all the code was mash-up into
    a single file.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=794273

 po/POTFILES.in         |    3 +
 src/Makefile.am        |    9 +-
 src/balls-preview.c    |  168 +++++
 src/balls-preview.h    |   35 +
 src/five-or-more-app.c |  695 ++++++++++++++++++++
 src/five-or-more-app.h |   51 ++
 src/five-or-more.c     | 1668 +-----------------------------------------------
 src/five-or-more.h     |   57 --
 src/game-area.c        | 1057 ++++++++++++++++++++++++++++++
 src/game-area.h        |   55 ++
 src/meson.build        |    6 +
 11 files changed, 2084 insertions(+), 1720 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index f354a02..980c576 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -9,3 +9,6 @@ data/org.gnome.five-or-more.gschema.xml
 data/translatable_themes.h
 src/five-or-more.c
 src/games-scores-dialog.c
+src/five-or-more-app.c
+src/game-area.c
+src/balls-preview.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 12edd52..79d7d95 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -2,7 +2,6 @@ bin_PROGRAMS = five-or-more
 
 five_or_more_SOURCES = \
        five-or-more.c  \
-       five-or-more.h  \
        games-file-list.c       \
        games-file-list.h       \
        games-gridframe.c       \
@@ -16,7 +15,13 @@ five_or_more_SOURCES =       \
        games-scores-dialog.c   \
        games-scores-dialog.h   \
        games-scores-backend.c  \
-       games-scores-backend.h
+       games-scores-backend.h \
+       five-or-more-app.h \
+       five-or-more-app.c \
+       balls-preview.c \
+       balls-preview.h \
+       game-area.h \
+       game-area.c
 
 five_or_more_CPPFLAGS = \
        -I$(top_srcdir) \
diff --git a/src/balls-preview.c b/src/balls-preview.c
new file mode 100644
index 0000000..c68e3e0
--- /dev/null
+++ b/src/balls-preview.c
@@ -0,0 +1,168 @@
+/* -*- mode:C; indent-tabs-mode:t; tab-width:8; c-basic-offset:8; -*- */
+
+/*
+ * Color lines for GNOME
+ * Copyright © 1999 Free Software Foundation
+ * Authors: Robert Szokovacs <szo appaloosacorp hu>
+ *          Szabolcs Ban <shooby gnome hu>
+ *          Karuna Grewal <karunagrewal98 gmail com>
+ * Copyright © 2007 Christian Persch
+ *
+ * This game 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, 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, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <locale.h>
+#include <math.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gdk/gdkkeysyms.h>
+
+#include "games-preimage.h"
+#include "balls-preview.h"
+#include "game-area.h"
+
+#define MAXNPIECES 10
+#define PREVIEW_IMAGE_WIDTH 20
+#define PREVIEW_IMAGE_HEIGHT 20
+
+static GtkImage* preview_images[MAXNPIECES];
+static GdkPixbuf* preview_pixbufs[MAXNPIECES];
+static int preview[MAXNPIECES];
+
+void
+init_preview (void)
+{
+  int i;
+  gint npieces = get_npieces();
+  for (i = 0; i < npieces; i++) {
+    preview[i] = g_rand_int_range (*get_rgen(), 1, get_ncolors() + 1);
+  }
+}
+
+void
+draw_preview (void)
+{
+  guint i;
+  gint npieces = get_npieces();
+  /* This function can be called before the images are initialized */
+  if (!GTK_IS_IMAGE (preview_images[0]))
+    return;
+
+  for (i = 0; i < MAXNPIECES; i++) {
+    if (i < npieces)
+      gtk_image_set_from_pixbuf (preview_images[i], preview_pixbufs[preview[i] - 1]);
+    else
+      gtk_image_clear (preview_images[i]);
+  }
+}
+
+void
+refresh_preview_surfaces (void)
+{
+  guint i;
+  GdkPixbuf *scaled = NULL;
+  GtkWidget *widget = GTK_WIDGET (preview_images[0]);
+  GtkStyleContext *context;
+  GdkRGBA bg;
+  cairo_t *cr;
+  GdkRectangle preview_rect;
+  cairo_surface_t *blank_preview_surface = NULL;
+  /* The balls rendered to a size appropriate for the preview. */
+  cairo_surface_t *preview_surface = NULL;
+
+  context = gtk_widget_get_style_context (widget);
+  gtk_style_context_get_background_color (context, gtk_style_context_get_state (context), &bg);
+
+  /* Like the refresh_pixmaps() function, we may be called before
+   * the window is ready. */
+  if (PREVIEW_IMAGE_HEIGHT == 0)
+    return;
+
+  preview_rect.x = 0;
+  preview_rect.y = 0;
+  preview_rect.width = PREVIEW_IMAGE_WIDTH;
+  preview_rect.height = PREVIEW_IMAGE_HEIGHT;
+
+  /* We create pixmaps for each of the ball colours and then
+   * set them as the background for each widget in the preview array.
+   * This code assumes that each preview window is identical. */
+  GamesPreimage *ball_preimage = get_ball_preimage();
+  if (ball_preimage)
+    scaled = games_preimage_render (ball_preimage, 4 * PREVIEW_IMAGE_WIDTH,
+                                    7 * PREVIEW_IMAGE_HEIGHT);
+
+  if (!scaled) {
+    scaled = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
+                             4 * PREVIEW_IMAGE_WIDTH, 7 * PREVIEW_IMAGE_HEIGHT);
+    gdk_pixbuf_fill (scaled, 0x00000000);
+  }
+
+  for (i = 0; i < 7; i++) {
+    preview_surface = gdk_window_create_similar_image_surface (gtk_widget_get_window (widget),
+                                                               CAIRO_FORMAT_ARGB32,
+                                                               PREVIEW_IMAGE_WIDTH, PREVIEW_IMAGE_HEIGHT, 1);
+    cr = cairo_create (preview_surface);
+    gdk_cairo_set_source_rgba (cr, &bg);
+    gdk_cairo_rectangle (cr, &preview_rect);
+    cairo_fill (cr);
+
+    gdk_cairo_set_source_pixbuf (cr, scaled, 0, -1.0 * PREVIEW_IMAGE_HEIGHT * i);
+    cairo_mask (cr, cairo_get_source (cr));
+
+    if (preview_pixbufs[i])
+      g_object_unref (preview_pixbufs[i]);
+
+    preview_pixbufs[i] = gdk_pixbuf_get_from_surface (preview_surface, 0, 0,
+                                                      PREVIEW_IMAGE_WIDTH, PREVIEW_IMAGE_HEIGHT);
+
+    cairo_destroy (cr);
+    cairo_surface_destroy (preview_surface);
+  }
+
+  blank_preview_surface = gdk_window_create_similar_surface (gtk_widget_get_window (widget),
+                                                             CAIRO_CONTENT_COLOR_ALPHA,
+                                                             PREVIEW_IMAGE_WIDTH, PREVIEW_IMAGE_HEIGHT);
+  cr = cairo_create (blank_preview_surface);
+  gdk_cairo_set_source_rgba (cr, &bg);
+  gdk_cairo_rectangle (cr, &preview_rect);
+  cairo_fill (cr);
+
+  cairo_surface_destroy (blank_preview_surface);
+  cairo_destroy (cr);
+  g_object_unref (scaled);
+}
+
+GtkImage **
+get_preview_images()
+{
+  return preview_images;
+}
+
+int *
+get_preview()
+{
+  return preview;
+}
+
+GdkPixbuf **
+get_preview_pixbufs()
+{
+  return preview_pixbufs;
+}
\ No newline at end of file
diff --git a/src/balls-preview.h b/src/balls-preview.h
new file mode 100644
index 0000000..13fa64f
--- /dev/null
+++ b/src/balls-preview.h
@@ -0,0 +1,35 @@
+/*
+ * Color lines for GNOME
+ * Copyright © 1999 Free Software Foundation
+ * Authors: Robert Szokovacs <szo appaloosacorp hu>
+ *          Szabolcs Ban <shooby gnome hu>
+ *          Karuna Grewal <karunagrewal98 gmail com>
+ * Copyright © 2007 Christian Persch
+ *
+ * This game 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, 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, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef BALLS_PREVIEW_H
+#define BALLS_PREVIEW_H
+
+#include <gtk/gtk.h>
+
+void        init_preview             (void);
+void        draw_preview             (void);
+void        refresh_preview_surfaces (void);
+GtkImage  **get_preview_images       ();
+int       * get_preview              ();
+GdkPixbuf **get_preview_pixbufs      ();
+
+#endif
\ No newline at end of file
diff --git a/src/five-or-more-app.c b/src/five-or-more-app.c
new file mode 100644
index 0000000..8c94ddc
--- /dev/null
+++ b/src/five-or-more-app.c
@@ -0,0 +1,695 @@
+/* -*- mode:C; indent-tabs-mode:t; tab-width:8; c-basic-offset:8; -*- */
+
+/*
+ * Color lines for GNOME
+ * Copyright © 1999 Free Software Foundation
+ * Authors: Robert Szokovacs <szo appaloosacorp hu>
+ *          Szabolcs Ban <shooby gnome hu>
+ *          Karuna Grewal <karunagrewal98 gmail com>
+ * Copyright © 2007 Christian Persch
+ *
+ * This game 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, 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, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <locale.h>
+#include <math.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gdk/gdkkeysyms.h>
+
+#include "games-file-list.h"
+#include "games-preimage.h"
+#include "games-gridframe.h"
+#include "games-scores.h"
+#include "games-scores-dialog.h"
+#include "game-area.h"
+#include "five-or-more-app.h"
+#include "balls-preview.h"
+
+#define DEFAULT_GAME_SIZE MEDIUM
+#define KEY_SIZE              "size"
+#define MAXNPIECES 10
+#define KEY_MOVE_TIMEOUT      "move-timeout"
+#define KEY_BACKGROUND_COLOR  "background-color"
+#define KEY_BALL_THEME        "ball-theme"
+
+static const GamesScoresCategory scorecats[] = {
+  { "Small",  NC_("board size", "Small")  },
+  { "Medium", NC_("board size", "Medium") },
+  { "Large",  NC_("board size", "Large")  }
+};
+
+enum {
+  UNSET = 0,
+  SMALL = 1,
+  MEDIUM,
+  LARGE,
+  MAX_SIZE,
+};
+
+static background backgnd = { { 0, 0, 0, 0}, NULL, 0 };
+static GtkWidget *gridframe;
+static GtkWidget *app, *headerbar, *restart_game_dialog, *pref_dialog;
+
+static char *ball_filename;
+static gint game_size = UNSET;
+static gboolean pref_dialog_done = FALSE;
+static GamesFileList *theme_file_list = NULL;
+static GtkWidget *size_radio_s, *size_radio_m, *size_radio_l;
+
+static int move_timeout = 100;
+static gboolean window_is_fullscreen = FALSE, window_is_maximized = FALSE;
+static gint window_width = 0, window_height = 0;
+static GamesScores *highscores;
+static GSettings *settings;
+static GtkBuilder *builder;
+static GtkBuilder *builder_preferences;
+
+static guint score = 0;
+static GtkWidget *scorelabel;
+
+/*getter funcs*/
+
+GSettings **
+get_settings ()
+{
+  return &settings;
+}
+
+const GamesScoresCategory *
+get_scorecats ()
+{
+  return scorecats;
+}
+
+gint *
+get_game_size ()
+{
+  return &game_size;
+}
+
+GtkWidget *
+get_gridframe ()
+{
+  return gridframe;
+}
+
+char *
+get_ball_filename ()
+{
+  return ball_filename;
+}
+
+background
+get_backgnd ()
+{
+  return backgnd;
+}
+
+int
+get_move_timeout ()
+{
+  return move_timeout;
+}
+
+GamesScores *
+get_highscores()
+{
+  return highscores;
+}
+
+void
+update_score (guint value)
+{
+  char string[20];
+  if(value)
+  score += value;
+  else
+  score = value;
+  g_snprintf (string, 19, "%d", score);
+  gtk_label_set_text (GTK_LABEL (scorelabel), string);
+}
+
+void
+set_status_message (gchar * message)
+{
+  gtk_header_bar_set_subtitle (GTK_HEADER_BAR (headerbar), message);
+}
+
+static void
+set_backgnd_color (const gchar * str)
+{
+  if (!str)
+    str = g_strdup ("#000000");
+
+  if (str != backgnd.name) {
+    g_free (backgnd.name);
+    backgnd.name = g_strdup (str);
+  }
+
+  if (!gdk_rgba_parse (&backgnd.color, backgnd.name)) {
+    gdk_rgba_parse (&backgnd.color, "#000000");
+  }
+}
+
+static void
+show_scores (gint pos)
+{
+  static GtkWidget *dialog;
+
+  if (dialog == NULL) {
+    dialog = games_scores_dialog_new (GTK_WINDOW (app), highscores, _("Five or More Scores"));
+    games_scores_dialog_set_category_description (GAMES_SCORES_DIALOG
+                                                  (dialog), _("_Board size:"));
+  }
+
+  if (pos > 0) {
+    games_scores_dialog_set_hilight (GAMES_SCORES_DIALOG (dialog), pos);
+  }
+
+  gtk_window_present (GTK_WINDOW (dialog));
+  gtk_dialog_run (GTK_DIALOG (dialog));
+  gtk_widget_hide (dialog);
+}
+
+static void
+load_properties (void)
+{
+  gchar *buf;
+  ball_filename = g_settings_get_string (settings, KEY_BALL_THEME);
+
+  move_timeout = g_settings_get_int (settings, KEY_MOVE_TIMEOUT);
+  if (move_timeout <= 0)
+    move_timeout = 100;
+
+  buf = g_settings_get_string (settings, KEY_BACKGROUND_COLOR); /* FIXMEchpe? */
+  set_backgnd_color (buf);
+  g_free (buf);
+  load_theme ();
+}
+
+void
+game_over (void)
+{
+  int pos;
+
+  set_status_message (_("Game Over!"));
+  if (score > 0)
+    pos = games_scores_add_plain_score (highscores, score);
+  show_scores (pos);
+}
+
+static void
+start_game (void)
+{
+  set_status_message (_("Match five objects of the same type in a row to score!"));
+  refresh_screen ();
+  update_score(0);
+  set_inmove (0);
+}
+
+static void
+conf_value_changed_cb (GSettings *settings, gchar *key)
+{
+  if (strcmp (key, KEY_BACKGROUND_COLOR) == 0) {
+    gchar *color;
+    color = g_settings_get_string (settings, KEY_BACKGROUND_COLOR);
+    if (color != NULL) {
+      set_backgnd_color (color);
+      g_free (color);
+    }
+  } else if (strcmp (key, KEY_BALL_THEME) == 0) {
+    gchar *theme_tmp = NULL;
+
+    theme_tmp = g_settings_get_string (settings, KEY_BALL_THEME);
+    if (theme_tmp) {
+      if (strcmp (theme_tmp, ball_filename) != 0) {
+        g_free (ball_filename);
+        ball_filename = theme_tmp;
+        load_theme ();
+        refresh_screen ();
+      } else
+        g_free (theme_tmp);
+    }
+    /* FIXME apply in the prefs dialog GUI */
+  } else if (strcmp (key, KEY_MOVE_TIMEOUT) == 0) {
+    gint timeout_tmp;
+
+    timeout_tmp = g_settings_get_int (settings, KEY_MOVE_TIMEOUT);
+    timeout_tmp = CLAMP (timeout_tmp, 1, 1000);
+    if (timeout_tmp != move_timeout)
+      move_timeout = timeout_tmp;
+
+  } else if (strcmp (key, KEY_SIZE) == 0) {
+    gint size_tmp;
+    size_tmp = g_settings_get_int (settings, KEY_SIZE);
+
+    if (size_tmp != game_size) {
+      set_sizes (size_tmp);
+      reset_game ();
+      start_game ();
+    }
+  }
+}
+
+static void
+init_config (void)
+{
+  g_signal_connect (settings, "changed",
+                    G_CALLBACK (conf_value_changed_cb), NULL);
+
+  game_size = g_settings_get_int (settings, KEY_SIZE);
+  if (game_size == UNSET)
+    game_size = DEFAULT_GAME_SIZE;
+
+  game_size = CLAMP (game_size, SMALL, MAX_SIZE - 1);
+
+  set_sizes (game_size);
+}
+
+static gboolean
+window_size_allocate_cb (GtkWidget *widget, GdkRectangle *allocation)
+{
+  if (!window_is_maximized && !window_is_fullscreen)
+    gtk_window_get_size (GTK_WINDOW (widget), &window_width, &window_height);
+
+  return FALSE;
+}
+
+static gboolean
+window_state_event_cb (GtkWidget *widget, GdkEventWindowState *event)
+{
+  if ((event->changed_mask & GDK_WINDOW_STATE_MAXIMIZED) != 0)
+    window_is_maximized = (event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) != 0;
+  if ((event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) != 0)
+    window_is_fullscreen = (event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN) != 0;
+  return FALSE;
+}
+
+
+void
+game_new_callback (GSimpleAction *action,
+                   GVariant *parameter,
+                   gpointer user_data)
+{
+  reset_game ();
+  start_game ();
+}
+
+void
+game_top_ten_callback (GSimpleAction *action,
+                       GVariant *parameter,
+                       gpointer user_data)
+{
+  show_scores (0);
+}
+
+
+static void
+set_selection (GtkWidget * widget, char *data)
+{
+  const gchar *entry;
+
+  entry = games_file_list_get_nth (theme_file_list,
+                                   gtk_combo_box_get_active (GTK_COMBO_BOX
+                                                             (widget)));
+  g_settings_set_string (settings, KEY_BALL_THEME, entry);
+}
+
+
+
+void
+pref_dialog_response (GtkDialog * dialog, gint response, gpointer data)
+{
+  gtk_widget_hide (GTK_WIDGET (dialog));
+}
+
+static void
+bg_color_callback (GtkWidget * widget, gpointer data)
+{
+  GdkRGBA c;
+  char str[64];
+
+  gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (widget), &c);
+
+  g_snprintf (str, sizeof (str), "#%04x%04x%04x", (int) (c.red * 65535 + 0.5), (int) (c.green * 65535 + 
0.5), (int) (c.blue * 65535 + 0.5));
+
+  g_settings_set_string (settings, KEY_BACKGROUND_COLOR, str);
+  //area,h
+  load_theme ();
+  //area.h
+  refresh_screen ();
+}
+
+static void
+size_callback (GtkWidget * widget, gpointer data)
+{
+  GtkWidget *size_radio, *content_area, *label;
+
+  game_size = g_settings_get_int (settings, KEY_SIZE);
+  if (pref_dialog_done && game_size != GPOINTER_TO_INT (data) && !restart_game_dialog) {
+    GtkDialogFlags flags = GTK_DIALOG_DESTROY_WITH_PARENT;
+
+    restart_game_dialog = gtk_message_dialog_new (GTK_WINDOW (pref_dialog),
+                                                 GTK_MESSAGE_WARNING,
+                                                 flags,
+                                                 GTK_BUTTONS_NONE,
+                                                 _("Are you sure you want to restart the game?"));
+
+    gtk_dialog_add_buttons (GTK_DIALOG (restart_game_dialog),
+                            _("_Cancel"), GTK_RESPONSE_CANCEL,
+                            _("_Restart"), GTK_RESPONSE_OK,
+                            NULL);
+
+    gint result = gtk_dialog_run (GTK_DIALOG (restart_game_dialog));
+    gtk_widget_destroy (restart_game_dialog);
+
+    switch (result) {
+    case GTK_RESPONSE_OK:
+      g_settings_set_int (settings, KEY_SIZE, GPOINTER_TO_INT (data));
+      break;
+    case GTK_RESPONSE_CANCEL:
+      switch (game_size) {
+      case SMALL:
+       size_radio = size_radio_s;
+       break;
+      case MEDIUM:
+       size_radio = size_radio_m;
+       break;
+      case LARGE:
+       size_radio = size_radio_l;
+       break;
+      }
+      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (size_radio), TRUE);
+    }
+
+    restart_game_dialog = NULL;
+  }
+}
+
+static GtkWidget *
+fill_menu (void)
+{
+  gchar *pixmap_dir;
+
+  if (theme_file_list)
+    g_object_unref (theme_file_list);
+
+  pixmap_dir = g_build_filename (DATA_DIRECTORY, "themes", NULL);
+  theme_file_list = games_file_list_new_images (pixmap_dir, NULL);
+  g_free (pixmap_dir);
+  games_file_list_transform_basename (theme_file_list);
+
+  return games_file_list_create_widget (theme_file_list, ball_filename,
+                                        GAMES_FILE_LIST_REMOVE_EXTENSION |
+                                        GAMES_FILE_LIST_REPLACE_UNDERSCORES);
+}
+
+static void
+set_fast_moves_callback (GtkWidget * widget, gpointer * data)
+{
+  gboolean is_on = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+  gint timeout = is_on ? 10 : 100;
+  g_settings_set_int (settings, KEY_MOVE_TIMEOUT, timeout);
+}
+
+void
+game_props_callback (GSimpleAction *action,
+                     GVariant *parameter,
+                     gpointer user_data)
+{
+  gchar *ui_path;
+  GError *error = NULL;
+  GtkWidget *omenu;
+  GtkWidget *grid;
+  GtkWidget *color_button;
+  GtkWidget *size_radio;
+  GtkWidget *fast_moves_checkbutton;
+
+  if (!pref_dialog) {
+    ui_path = g_build_filename (DATA_DIRECTORY, "five-or-more-preferences.ui", NULL);
+    builder_preferences = gtk_builder_new ();
+    gtk_builder_add_from_file (builder_preferences, ui_path, &error);
+    g_free (ui_path);
+
+    if (error) {
+      g_critical ("Unable to load the user interface file: %s", error->message);
+      g_error_free (error);
+      g_assert_not_reached ();
+    }
+
+    pref_dialog = GTK_WIDGET (gtk_builder_get_object (builder_preferences, "preferences_dialog"));
+    g_signal_connect (pref_dialog, "response",
+                      G_CALLBACK (pref_dialog_response), NULL);
+    g_signal_connect (pref_dialog, "delete-event",
+                      G_CALLBACK (gtk_widget_hide), NULL);
+
+    grid = GTK_WIDGET (gtk_builder_get_object (builder_preferences, "grid1"));
+    omenu = fill_menu ();
+    gtk_widget_show_all (GTK_WIDGET (omenu));
+    gtk_grid_attach (GTK_GRID (grid), GTK_WIDGET (omenu), 1, 0, 1, 1);
+    g_signal_connect (omenu, "changed",
+                      G_CALLBACK (set_selection), NULL);
+
+    color_button = GTK_WIDGET (gtk_builder_get_object (builder_preferences, "colorbutton1"));
+    gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (color_button), &backgnd.color);
+    g_signal_connect (color_button, "color-set",
+                      G_CALLBACK (bg_color_callback), NULL);
+
+    size_radio = GTK_WIDGET (gtk_builder_get_object (builder_preferences, "radiobutton_small"));
+    size_radio_s = size_radio;
+    g_signal_connect (size_radio, "clicked",
+                      G_CALLBACK (size_callback), GINT_TO_POINTER (1));
+    if (game_size == SMALL)
+      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (size_radio), TRUE);
+
+    size_radio = GTK_WIDGET (gtk_builder_get_object (builder_preferences, "radiobutton_medium"));
+    size_radio_m = size_radio;
+    g_signal_connect (size_radio, "clicked",
+                      G_CALLBACK (size_callback), GINT_TO_POINTER (2));
+    if (game_size == MEDIUM)
+      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (size_radio), TRUE);
+
+    size_radio = GTK_WIDGET (gtk_builder_get_object (builder_preferences, "radiobutton_large"));
+    size_radio_l = size_radio;
+    g_signal_connect (size_radio, "clicked",
+                      G_CALLBACK (size_callback), GINT_TO_POINTER (3));
+    if (game_size == LARGE)
+      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (size_radio), TRUE);
+
+    fast_moves_checkbutton = GTK_WIDGET (gtk_builder_get_object (builder_preferences, 
"checkbutton_fast_moves"));
+    if (move_timeout == 10) {
+      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fast_moves_checkbutton), TRUE);
+    }
+
+    g_signal_connect (fast_moves_checkbutton, "clicked",
+                      G_CALLBACK (set_fast_moves_callback), NULL);
+
+    g_object_unref (G_OBJECT (builder_preferences));
+
+    pref_dialog_done = TRUE;
+    gtk_window_set_transient_for (GTK_WINDOW (pref_dialog), GTK_WINDOW (app));
+  }
+  gtk_dialog_run (GTK_DIALOG (pref_dialog));
+}
+
+void
+game_help_callback (GSimpleAction *action,
+                    GVariant *parameter,
+                    gpointer user_data)
+{
+  GError *error = NULL;
+
+  gtk_show_uri (gtk_widget_get_screen (GTK_WIDGET (app)), "help:five-or-more", gtk_get_current_event_time 
(), &error);
+  if (error)
+    g_warning ("Failed to show help: %s", error->message);
+  g_clear_error (&error);
+}
+
+void
+game_about_callback (GSimpleAction *action,
+                     GVariant *parameter,
+                     gpointer user_data)
+{
+  const gchar *authors[] = { "Robert Szokovacs <szo appaloosacorp hu>",
+    "Szabolcs B\xc3\xa1n <shooby gnome hu>",
+    NULL
+  };
+
+  const gchar *documenters[] = { "Tiffany Antopolski",
+                                 "Lanka Rathnayaka",
+    NULL
+  };
+
+  gtk_show_about_dialog (GTK_WINDOW (app),
+                         "program-name", _("Five or More"),
+                         "version", VERSION,
+                         "comments", _("GNOME port of the once-popular Color Lines game"),
+                         "copyright",
+                         "Copyright © 1997–2008 Free Software Foundation, Inc.\n Copyright © 2013–2014 
Michael Catanzaro",
+                         "license-type", GTK_LICENSE_GPL_2_0,
+                         "authors", authors,
+                         "documenters", documenters,
+                         "translator-credits", _("translator-credits"),
+                         "logo-icon-name", "five-or-more",
+                         "website", "https://wiki.gnome.org/Apps/Five%20or%20more";,
+                         NULL);
+}
+
+void
+game_quit_callback (GSimpleAction *action,
+                    GVariant *parameter,
+                    gpointer user_data)
+{
+  g_application_quit (G_APPLICATION (user_data));
+}
+
+void
+startup_cb (GApplication *application)
+{
+  gchar *ui_path;
+  GtkWidget *hbox;
+  GtkWidget *preview_hbox;
+  GtkWidget *new_game_button;
+  guint i;
+  GError *error = NULL;
+
+  GActionEntry app_actions[] = {
+    { "new-game", game_new_callback },
+    { "scores", game_top_ten_callback },
+    { "preferences", game_props_callback },
+    { "help", game_help_callback },
+    { "about", game_about_callback },
+    { "quit", game_quit_callback }
+  };
+
+  g_action_map_add_action_entries (G_ACTION_MAP (application),
+                                   app_actions, G_N_ELEMENTS (app_actions),
+                                   application);
+
+  gtk_application_add_accelerator (GTK_APPLICATION (application), "<Primary>N", "app.new-game", NULL);
+
+  settings = g_settings_new ("org.gnome.five-or-more");
+
+  highscores = games_scores_new ("five-or-more",
+                                 scorecats, G_N_ELEMENTS (scorecats),
+                                 "board size", NULL,
+                                 0 /* default category */,
+                                 GAMES_SCORES_STYLE_PLAIN_DESCENDING);
+  init_config ();
+  builder = gtk_builder_new ();
+  ui_path = g_build_filename (DATA_DIRECTORY, "menu.ui", NULL);
+  gtk_builder_add_from_file (builder, ui_path, &error);
+  g_free (ui_path);
+
+    if (error) {
+    g_critical ("Unable to load the application menu file: %s", error->message);
+    g_error_free (error);
+  } else {
+    gtk_application_set_app_menu (GTK_APPLICATION (application),
+                                  G_MENU_MODEL (gtk_builder_get_object (builder, "appmenu")));
+  }
+
+  ui_path = g_build_filename (DATA_DIRECTORY, "five-or-more.ui", NULL);
+  gtk_builder_add_from_file (builder, ui_path, &error);
+  g_free (ui_path);
+
+  if (error) {
+    g_critical ("Unable to load the user interface file: %s", error->message);
+    g_error_free (error);
+    g_assert_not_reached ();
+  }
+
+  app = GTK_WIDGET (gtk_builder_get_object (builder, "glines_window"));
+  gtk_window_set_icon_name (GTK_WINDOW (app), "five-or-more");
+  g_signal_connect (GTK_WINDOW (app), "size-allocate", G_CALLBACK (window_size_allocate_cb), NULL);
+  g_signal_connect (GTK_WINDOW (app), "window-state-event", G_CALLBACK (window_state_event_cb), NULL);
+  gtk_window_set_default_size (GTK_WINDOW (app), g_settings_get_int (settings, "window-width"), 
g_settings_get_int (settings, "window-height"));
+  if (g_settings_get_boolean (settings, "window-is-maximized"))
+    gtk_window_maximize (GTK_WINDOW (app));
+  gtk_container_set_border_width (GTK_CONTAINER (app), 20);
+  gtk_application_add_window (GTK_APPLICATION (application), GTK_WINDOW (app));
+
+  headerbar = GTK_WIDGET (gtk_builder_get_object (builder, "headerbar"));
+
+  GtkImage **preview_images = get_preview_images();
+  preview_hbox = GTK_WIDGET (gtk_builder_get_object (builder, "preview_hbox"));
+  for (i = 0; i < MAXNPIECES; i++) {
+    //preview images getter req this is defiend in src or here
+    preview_images[i] = GTK_IMAGE (gtk_image_new ());
+    gtk_box_pack_start (GTK_BOX (preview_hbox), GTK_WIDGET (preview_images[i]), FALSE, FALSE, 0);
+    gtk_widget_realize (GTK_WIDGET (preview_images[i]));
+  }
+
+  scorelabel = GTK_WIDGET (gtk_builder_get_object (builder, "scorelabel"));
+
+  hbox = GTK_WIDGET (gtk_builder_get_object (builder, "hbox"));
+
+  GtkWidget *draw_area = game_area_init ();
+
+  gridframe = games_grid_frame_new (get_hfieldsize(), get_vfieldsize());
+  games_grid_frame_set_padding (GAMES_GRID_FRAME (gridframe), 1, 1);
+  gtk_container_add (GTK_CONTAINER (gridframe), draw_area);
+  gtk_box_pack_start (GTK_BOX (hbox), gridframe, TRUE, TRUE, 0);
+
+  new_game_button = GTK_WIDGET (gtk_builder_get_object (builder, "new_game_button"));
+
+  load_properties ();
+
+  gtk_builder_connect_signals (builder, NULL);
+
+  g_object_unref (G_OBJECT (builder));
+}
+
+
+void
+activate_cb (GApplication *application)
+{
+  reset_game ();
+  gtk_widget_show_all (app);
+  start_game ();
+}
+
+void
+shutdown_cb (GApplication *application)
+{
+  int i = 0;
+  GtkImage **preview_images = get_preview_images();
+  GdkPixbuf **preview_pixbufs = get_preview_pixbufs();
+  for (i = 0; i < G_N_ELEMENTS (preview_images); i++)
+    if (preview_pixbufs[i])
+      g_object_unref (preview_pixbufs[i]);
+
+  GamesPreimage *ball_preimage = get_ball_preimage();
+  g_clear_object (&ball_preimage);
+  g_object_unref (highscores);
+
+  g_settings_set_int (settings, "window-width", window_width);
+  g_settings_set_int (settings, "window-height", window_height);
+  g_settings_set_boolean (settings, "window-is-maximized", window_is_maximized);
+}
+
+void
+set_application_callbacks(GtkApplication *application)
+{
+  g_signal_connect (application, "startup", G_CALLBACK (startup_cb), NULL);
+  g_signal_connect (application, "activate", G_CALLBACK (activate_cb), NULL);
+  g_signal_connect (application, "shutdown", G_CALLBACK (shutdown_cb), NULL);
+}
\ No newline at end of file
diff --git a/src/five-or-more-app.h b/src/five-or-more-app.h
new file mode 100644
index 0000000..6e9a6b6
--- /dev/null
+++ b/src/five-or-more-app.h
@@ -0,0 +1,51 @@
+/*
+ * Color lines for GNOME
+ * Copyright © 1999 Free Software Foundation
+ * Authors: Robert Szokovacs <szo appaloosacorp hu>
+ *          Szabolcs Ban <shooby gnome hu>
+ *          Karuna Grewal <karunagrewal98 gmail com>
+ * Copyright © 2007 Christian Persch
+ *
+ * This game 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, 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, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef FIVE_OR_MORE_APP_H
+#define FIVE_OR_MORE_APP_H
+
+#include <gtk/gtk.h>
+#include "games-scores.h"
+
+typedef struct _background background;
+struct _background{
+  GdkRGBA color;
+  gchar *name;
+  gint set;
+} ;
+
+GamesScores                 *get_highscores             ();
+GtkWidget                   *get_gridframe              ();
+char                        *get_ball_filename          ();
+background                   get_backgnd                ();
+void                         set_status_message         (gchar * message);
+void                         game_over                  (void);
+void                         set_application_callbacks  (GtkApplication *application);
+gint                        *get_game_size              ();
+const GamesScoresCategory   *get_scorecats              ();
+GSettings                  **get_settings               ();
+int                          get_move_timeout           ();
+void                         game_props_callback        (GSimpleAction *action,
+                                                         GVariant *parameter,
+                                                         gpointer user_data);
+void                         update_score               (guint value);
+#endif
\ No newline at end of file
diff --git a/src/five-or-more.c b/src/five-or-more.c
index f2a3dc7..cc9e1fe 100644
--- a/src/five-or-more.c
+++ b/src/five-or-more.c
@@ -34,1662 +34,8 @@
 #include <gdk-pixbuf/gdk-pixbuf.h>
 #include <gdk/gdkkeysyms.h>
 
-#include "five-or-more.h"
-#include "games-file-list.h"
-#include "games-preimage.h"
-#include "games-gridframe.h"
-#include "games-scores.h"
-#include "games-scores-dialog.h"
-
-#define KEY_BACKGROUND_COLOR  "background-color"
-#define KEY_BALL_THEME        "ball-theme"
-#define KEY_MOVE_TIMEOUT      "move-timeout"
-#define KEY_SIZE              "size"
-
-#define KEY_SAVED_SCORE   "score"
-#define KEY_SAVED_FIELD   "field"
-#define KEY_SAVED_PREVIEW "preview"
-
-#define MAXNPIECES 10
-#define MAXFIELDSIZE 30
-#define DEFAULT_GAME_SIZE MEDIUM
-#define DEFAULT_BALL_THEME "balls.svg"
-
-#define PREVIEW_IMAGE_WIDTH 20
-#define PREVIEW_IMAGE_HEIGHT 20
-
-enum {
-  UNSET = 0,
-  SMALL = 1,
-  MEDIUM,
-  LARGE,
-  MAX_SIZE,
-};
-
-/* Keep these in sync with the enum above. */
-static const gint field_sizes[MAX_SIZE][4] = {
-  {-1, -1, -1, -1}, /* This is a dummy entry. */
-  {7, 7, 5, 3},     /* SMALL */
-  {9, 9, 7, 3},     /* MEDIUM */
-  {20, 15, 7, 7}    /* LARGE */
-};
-
-static const GamesScoresCategory scorecats[] = {
-  { "Small",  NC_("board size", "Small")  },
-  { "Medium", NC_("board size", "Medium") },
-  { "Large",  NC_("board size", "Large")  }
-};
-
-static GamesScores *highscores;
-static GSettings *settings;
-static GtkBuilder *builder;
-static GtkBuilder *builder_preferences;
-
-static gint hfieldsize;
-static gint vfieldsize;
-static gint ncolors;
-static gint npieces;
-static gint game_size = UNSET;
-static gboolean pref_dialog_done = FALSE;
-
-static GRand *rgen;
-
-static GtkWidget *draw_area;
-static GtkWidget *app, *headerbar, *pref_dialog, *gridframe, *restart_game_dialog;
-static GtkWidget *size_radio_s, *size_radio_m, *size_radio_l;
-
-static gint window_width = 0, window_height = 0;
-static gboolean window_is_fullscreen = FALSE, window_is_maximized = FALSE;
-
-static field_props field[MAXFIELDSIZE * MAXFIELDSIZE];
-
-/* Pre-rendering image data prepared from file. */
-static GamesPreimage *ball_preimage = NULL;
-/* The tile images with balls rendered on them. */
-static cairo_surface_t *ball_surface = NULL;
-
-static GtkImage* preview_images[MAXNPIECES];
-static GdkPixbuf* preview_pixbufs[MAXNPIECES];
-
-/* A cairo_surface_t of a blank tile. */
-static cairo_surface_t *blank_surface = NULL;
-
-static GamesFileList *theme_file_list = NULL;
-
-static int active = -1;
-static int target = -1;
-static int inmove = 0;
-static guint score = 0;
-static int cursor_x = MAXFIELDSIZE / 2;
-static int cursor_y = MAXFIELDSIZE / 2;
-static gboolean show_cursor = FALSE;
-
-static int boxsize;
-
-static int move_timeout = 100;
-static int animate_id = 0;
-static int preview[MAXNPIECES];
-static char *ball_filename;
-static GtkWidget *scorelabel;
-static scoretable sctab[] =
-  { {5, 10}, {6, 12}, {7, 18}, {8, 28}, {9, 42}, {10, 82}, {11, 108}, {12,
-                                                                       138},
-  {13, 172}, {14, 210}, {0, 0} };
-
-static struct {
-  GdkRGBA color;
-  gchar *name;
-  gint set;
-} backgnd = { { 0, 0, 0, 0}, NULL, 0 };
-
-static gchar *warning_message = NULL;
-
-static void
-set_status_message (gchar * message)
-{
-  gtk_header_bar_set_subtitle (GTK_HEADER_BAR (headerbar), message);
-}
-
-static void
-show_image_warning (gchar * message)
-{
-  GtkWidget *dialog;
-  GtkWidget *button;
-
-  dialog = gtk_message_dialog_new (GTK_WINDOW (app),
-                                   GTK_DIALOG_MODAL,
-                                   GTK_MESSAGE_WARNING,
-                                   GTK_BUTTONS_CLOSE,
-                                   "%s",_("Could not load theme"));
-
-  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
-                                            "%s", message);
-
-  button = gtk_dialog_add_button (GTK_DIALOG (dialog),
-                                  _("Preferences"), GTK_RESPONSE_ACCEPT);
-
-  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
-
-  g_signal_connect (button, "clicked", G_CALLBACK (game_props_callback),
-                    NULL);
-
-  gtk_dialog_run (GTK_DIALOG (dialog));
-  gtk_widget_destroy (dialog);
-}
-
-static GamesPreimage *
-load_image (gchar * fname)
-{
-  GamesPreimage *preimage;
-  gchar *path;
-  GError *error = NULL;
-
-  path = g_build_filename (DATA_DIRECTORY, "themes", fname, NULL);
-  if (!g_file_test (path, G_FILE_TEST_EXISTS)) {
-    warning_message = g_strdup_printf (_("Unable to locate file:\n%s\n\n"
-                                         "The default theme will be loaded instead."),
-                                       fname);
-
-    path = g_build_filename (DATA_DIRECTORY, "themes", "balls.svg", NULL);
-    if (!g_file_test (path, G_FILE_TEST_EXISTS)) {
-      g_free (warning_message);
-      warning_message = g_strdup_printf (_("Unable to locate file:\n%s\n\n"
-                                           "Please check that Five or More is installed correctly."),
-                                         fname);
-    }
-  }
-
-  preimage = games_preimage_new_from_file (path, &error);
-  g_free (path);
-
-  if (error) {
-    warning_message = g_strdup (error->message);
-    g_error_free (error);
-  }
-
-  return preimage;
-}
-
-static void
-refresh_pixmaps (void)
-{
-  cairo_t *cr, *cr_blank;
-  GdkPixbuf *ball_pixbuf = NULL;
-
-  /* Since we get called both by configure and after loading an image.
-   * it is possible the pixmaps aren't initialised. If they aren't
-   * we don't do anything. */
-  if (!ball_surface)
-    return;
-
-  if (!boxsize)
-    return;
-
-  if (ball_preimage) {
-    ball_pixbuf = games_preimage_render (ball_preimage, 4 * boxsize,
-                                         7 * boxsize);
-
-    /* Handle rendering problems. */
-    if (!ball_pixbuf) {
-      g_object_unref (ball_preimage);
-      ball_preimage = NULL;
-
-      if (!warning_message) {
-        warning_message = g_strdup ("The selected theme failed to render.\n\n"
-                                    "Please check that Five or More is installed correctly.");
-      }
-    }
-  }
-
-  if (!ball_pixbuf) {
-    ball_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
-                                  4 * boxsize, 7 * boxsize);
-    gdk_pixbuf_fill (ball_pixbuf, 0x00000000);
-  }
-
-  if (warning_message)
-    show_image_warning (warning_message);
-  g_free (warning_message);
-  warning_message = NULL;
-
-  cr = cairo_create (ball_surface);
-  gdk_cairo_set_source_rgba (cr, &backgnd.color);
-
-  cairo_rectangle (cr, 0, 0, boxsize * 4, boxsize * 7);
-  cairo_fill (cr);
-
-  gdk_cairo_set_source_pixbuf (cr, ball_pixbuf, 0, 0);
-  cairo_mask (cr, cairo_get_source (cr));
-  g_object_unref (ball_pixbuf);
-
-  cairo_destroy (cr);
-
-  cr_blank = cairo_create (blank_surface);
-  gdk_cairo_set_source_rgba (cr_blank, &backgnd.color);
-
-  cairo_rectangle (cr_blank, 0, 0, boxsize, boxsize);
-  cairo_fill (cr_blank);
-
-  cairo_destroy (cr_blank);
-}
-
-static void
-refresh_preview_surfaces (void)
-{
-  guint i;
-  GdkPixbuf *scaled = NULL;
-  GtkWidget *widget = GTK_WIDGET (preview_images[0]);
-  GtkStyleContext *context;
-  GdkRGBA bg;
-  cairo_t *cr;
-  GdkRectangle preview_rect;
-  cairo_surface_t *blank_preview_surface = NULL;
-  /* The balls rendered to a size appropriate for the preview. */
-  cairo_surface_t *preview_surface = NULL;
-
-  context = gtk_widget_get_style_context (widget);
-  gtk_style_context_get_background_color (context, gtk_style_context_get_state (context), &bg);
-
-  /* Like the refresh_pixmaps() function, we may be called before
-   * the window is ready. */
-  if (PREVIEW_IMAGE_HEIGHT == 0)
-    return;
-
-  preview_rect.x = 0;
-  preview_rect.y = 0;
-  preview_rect.width = PREVIEW_IMAGE_WIDTH;
-  preview_rect.height = PREVIEW_IMAGE_HEIGHT;
-
-  /* We create pixmaps for each of the ball colours and then
-   * set them as the background for each widget in the preview array.
-   * This code assumes that each preview window is identical. */
-
-  if (ball_preimage)
-    scaled = games_preimage_render (ball_preimage, 4 * PREVIEW_IMAGE_WIDTH,
-                                    7 * PREVIEW_IMAGE_HEIGHT);
-
-  if (!scaled) {
-    scaled = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
-                             4 * PREVIEW_IMAGE_WIDTH, 7 * PREVIEW_IMAGE_HEIGHT);
-    gdk_pixbuf_fill (scaled, 0x00000000);
-  }
-
-  for (i = 0; i < 7; i++) {
-    preview_surface = gdk_window_create_similar_image_surface (gtk_widget_get_window (widget),
-                                                               CAIRO_FORMAT_ARGB32,
-                                                               PREVIEW_IMAGE_WIDTH, PREVIEW_IMAGE_HEIGHT, 1);
-    cr = cairo_create (preview_surface);
-    gdk_cairo_set_source_rgba (cr, &bg);
-    gdk_cairo_rectangle (cr, &preview_rect);
-    cairo_fill (cr);
-
-    gdk_cairo_set_source_pixbuf (cr, scaled, 0, -1.0 * PREVIEW_IMAGE_HEIGHT * i);
-    cairo_mask (cr, cairo_get_source (cr));
-
-    if (preview_pixbufs[i])
-      g_object_unref (preview_pixbufs[i]);
-
-    preview_pixbufs[i] = gdk_pixbuf_get_from_surface (preview_surface, 0, 0,
-                                                      PREVIEW_IMAGE_WIDTH, PREVIEW_IMAGE_HEIGHT);
-
-    cairo_destroy (cr);
-    cairo_surface_destroy (preview_surface);
-  }
-
-  blank_preview_surface = gdk_window_create_similar_surface (gtk_widget_get_window (widget),
-                                                             CAIRO_CONTENT_COLOR_ALPHA,
-                                                             PREVIEW_IMAGE_WIDTH, PREVIEW_IMAGE_HEIGHT);
-  cr = cairo_create (blank_preview_surface);
-  gdk_cairo_set_source_rgba (cr, &bg);
-  gdk_cairo_rectangle (cr, &preview_rect);
-  cairo_fill (cr);
-
-  cairo_surface_destroy (blank_preview_surface);
-  cairo_destroy (cr);
-  g_object_unref (scaled);
-}
-
-static void
-draw_all_balls (GtkWidget * widget)
-{
-  gdk_window_invalidate_rect (gtk_widget_get_window (widget), NULL, FALSE);
-}
-
-static void
-start_animation (void)
-{
-  int ms;
-
-  ms = (inmove ? move_timeout : 100);
-  if (animate_id == 0)
-    animate_id = g_timeout_add (ms, animate, draw_area);
-}
-
-void
-set_inmove (int i)
-{
-  if (inmove != i) {
-    inmove = i;
-    if (animate_id)
-      g_source_remove (animate_id);
-    animate_id = 0;
-    start_animation ();
-  }
-}
-
-static void
-reset_game (void)
-{
-  int i;
-
-  for (i = 0; i < hfieldsize * vfieldsize; i++) {
-    field[i].color = 0;
-    field[i].phase = 0;
-    field[i].active = 0;
-    field[i].pathsearch = -1;
-  }
-  score = 0;
-  init_preview ();
-  init_new_balls (npieces, -1);
-}
-
-static void
-refresh_screen (void)
-{
-  draw_all_balls (draw_area);
-  draw_preview ();
-}
-
-static void
-start_game (void)
-{
-  char string[20];
-
-  set_status_message (_("Match five objects of the same type in a row to score!"));
-  refresh_screen ();
-  active = -1;
-  target = -1;
-  inmove = -1;
-  g_snprintf (string, 19, "%d", score);
-  gtk_label_set_text (GTK_LABEL (scorelabel), string);
-  set_inmove (0);
-}
-
-static void
-reset_pathsearch (void)
-{
-  int i;
-
-  for (i = 0; i < hfieldsize * vfieldsize; i++)
-    field[i].pathsearch = -1;
-}
-
-void
-init_preview (void)
-{
-  int i;
-
-  for (i = 0; i < npieces; i++) {
-    preview[i] = g_rand_int_range (rgen, 1, ncolors + 1);
-  }
-}
-
-void
-draw_preview (void)
-{
-  guint i;
-
-  /* This function can be called before the images are initialized */
-  if (!GTK_IS_IMAGE (preview_images[0]))
-    return;
-
-  for (i = 0; i < MAXNPIECES; i++) {
-    if (i < npieces)
-      gtk_image_set_from_pixbuf (preview_images[i], preview_pixbufs[preview[i] - 1]);
-    else
-      gtk_image_clear (preview_images[i]);
-  }
-}
-
-void
-game_new_callback (GSimpleAction *action,
-                   GVariant *parameter,
-                   gpointer user_data)
-{
-  reset_game ();
-  start_game ();
-}
-
-static void
-show_scores (gint pos)
-{
-  static GtkWidget *dialog;
-
-  if (dialog == NULL) {
-    dialog = games_scores_dialog_new (GTK_WINDOW (app), highscores, _("Five or More Scores"));
-    games_scores_dialog_set_category_description (GAMES_SCORES_DIALOG
-                                                  (dialog), _("_Board size:"));
-  }
-
-  if (pos > 0) {
-    games_scores_dialog_set_hilight (GAMES_SCORES_DIALOG (dialog), pos);
-  }
-
-  gtk_window_present (GTK_WINDOW (dialog));
-  gtk_dialog_run (GTK_DIALOG (dialog));
-  gtk_widget_hide (dialog);
-}
-
-static void
-game_over (void)
-{
-  int pos;
-
-  set_status_message (_("Game Over!"));
-  if (score > 0)
-    pos = games_scores_add_plain_score (highscores, score);
-  show_scores (pos);
-}
-
-static int
-spaces_left (void)
-{
-  int i, j;
-
-  j = 0;
-
-  for (i = 0; i < hfieldsize * vfieldsize; i++) {
-    if (field[i].color == 0)
-      j++;
-  }
-
-  return j;
-}
-
-static int
-check_gameover (void)
-{
-  if (spaces_left () > 0)
-    return 1;
-
-  game_over ();
-
-  return -1;
-}
-
-int
-init_new_balls (int num, int prev)
-{
-  int i, j = -1;
-  gfloat num_boxes = hfieldsize * vfieldsize;
-  for (i = 0; i < num;) {
-    j = g_rand_int_range (rgen, 0, num_boxes);
-    if (field[j].color == 0) {
-      field[j].color = (prev == -1) ?
-        g_rand_int_range (rgen, 1, ncolors + 1) : preview[prev];
-      i++;
-    }
-  }
-  return j;
-}
-
-void
-draw_box (GtkWidget * widget, int x, int y)
-{
-  gtk_widget_queue_draw_area (widget, x * boxsize, y * boxsize,
-                              boxsize, boxsize);
-}
-
-static int
-route (int num)
-{
-  int i;
-  int flag = 0;
-
-  if (field[target].pathsearch == num)
-    return 1;
-  for (i = 0; i < hfieldsize * vfieldsize; i++) {
-    if (field[i].pathsearch == num) {
-      flag = 1;
-      if ((i / hfieldsize > 0) && (field[i - hfieldsize].pathsearch == -1)
-          && (field[i - hfieldsize].color == 0))
-        field[i - hfieldsize].pathsearch = num + 1;
-      if ((i / hfieldsize < vfieldsize - 1)
-          && (field[i + hfieldsize].pathsearch == -1)
-          && (field[i + hfieldsize].color == 0))
-        field[i + hfieldsize].pathsearch = num + 1;
-      if ((i % hfieldsize > 0) && (field[i - 1].pathsearch == -1)
-          && (field[i - 1].color == 0))
-        field[i - 1].pathsearch = num + 1;
-      if ((i % hfieldsize < hfieldsize - 1) && (field[i + 1].pathsearch == -1)
-          && (field[i + 1].color == 0)) {
-        field[i + 1].pathsearch = num + 1;
-      }
-    }
-  }
-  if (flag == 0)
-    return 0;
-  return 2;
-}
-
-static void
-fix_route (int num, int pos)
-{
-  int i;
-
-  for (i = 0; i < hfieldsize * vfieldsize; i++)
-    if ((i != pos) && (field[i].pathsearch == num))
-      field[i].pathsearch = -1;
-  if (num < 2)
-    return;
-  if ((pos / hfieldsize > 0)
-      && (field[pos - hfieldsize].pathsearch == num - 1))
-    fix_route (num - 1, pos - hfieldsize);
-  if ((pos % hfieldsize > 0) && (field[pos - 1].pathsearch == num - 1))
-    fix_route (num - 1, pos - 1);
-  if ((pos / hfieldsize < vfieldsize - 1)
-      && (field[pos + hfieldsize].pathsearch == num - 1))
-    fix_route (num - 1, pos + hfieldsize);
-  if ((pos % hfieldsize < hfieldsize - 1)
-      && (field[pos + 1].pathsearch == num - 1))
-    fix_route (num - 1, pos + 1);
-}
-
-int
-find_route (void)
-{
-  int i = 0;
-  int j = 0;
-
-  field[active].pathsearch = i;
-  while ((j = route (i))) {
-    if (j == 1) {
-      fix_route (i, target);
-      return 1;
-    }
-    i++;
-  }
-  return 0;
-}
-
-static void
-deactivate (GtkWidget * widget, int x, int y)
-{
-  field[active].active = 0;
-  field[active].phase = 0;
-  draw_box (widget, x, y);
-  active = -1;
-}
-
-static void
-cell_clicked (GtkWidget * widget, int fx, int fy)
-{
-  int x, y;
-
-  set_status_message (NULL);
-  if (field[fx + fy * hfieldsize].color == 0) {
-    /* Clicked on an empty field */
-
-    if ((active != -1) && (inmove != 1)) {
-      /* We have an active ball, and it's not
-       * already in move. Therefore we should begin
-       * the moving sequence */
-
-      target = fx + fy * hfieldsize;
-      if (find_route ()) {
-        /* We found a route to the new position */
-
-        set_inmove (1);
-      } else {
-        /* Can't move there! */
-        set_status_message (_("You can’t move there!"));
-        reset_pathsearch ();
-        target = -1;
-      }
-    }
-  } else {
-    /* Clicked on a ball */
-
-    if ((fx + fy * hfieldsize) == active) {
-      /* It's active, so let's deactivate it! */
-
-      deactivate (widget, fx, fy);
-    } else {
-      /* It's not active, so let's activate it! */
-
-      if (active != -1) {
-        /* There is an other active ball, we should deactivate it first! */
-
-        x = active % hfieldsize;
-        y = active / hfieldsize;
-        deactivate (widget, x, y);
-      }
-
-      active = fx + fy * hfieldsize;
-      field[active].active = 1;
-      start_animation();
-    }
-  }
-
-}
-
-static gint
-button_press_event (GtkWidget * widget, GdkEvent * event)
-{
-  int x, y;
-  int fx, fy;
-
-  if (inmove)
-    return TRUE;
-
-  /* Ignore the 2BUTTON and 3BUTTON events. */
-  if (event->type != GDK_BUTTON_PRESS)
-    return TRUE;
-
-  if (show_cursor) {
-    show_cursor = FALSE;
-    draw_box (draw_area, cursor_x, cursor_y);
-  }
-
-  fx = event->button.x / boxsize;
-  fy = event->button.y / boxsize;
-
-  /* If we click on the outer border pixels, the previous calculation
-   * will be wrong and we must correct. */
-  fx = CLAMP (fx, 0, hfieldsize - 1);
-  fy = CLAMP (fy, 0, vfieldsize - 1);
-
-  cursor_x = fx;
-  cursor_y = fy;
-
-  cell_clicked (widget, fx, fy);
-
-  return TRUE;
-}
-
-static void
-move_cursor (int dx, int dy)
-{
-  int old_x = cursor_x;
-  int old_y = cursor_y;
-
-  if (!show_cursor) {
-    show_cursor = TRUE;
-    draw_box (draw_area, cursor_x, cursor_y);
-  }
-
-  cursor_x = cursor_x + dx;
-  if (cursor_x < 0)
-    cursor_x = 0;
-  if (cursor_x >= hfieldsize)
-    cursor_x = hfieldsize - 1;
-  cursor_y = cursor_y + dy;
-  if (cursor_y < 0)
-    cursor_y = 0;
-  if (cursor_y >= vfieldsize)
-    cursor_y = vfieldsize - 1;
-
-  if (cursor_x == old_x && cursor_y == old_y)
-    return;
-
-  draw_box (draw_area, old_x, old_y);
-  draw_box (draw_area, cursor_x, cursor_y);
-}
-
-static gboolean
-key_press_event (GtkWidget * widget, GdkEventKey * event, void *d)
-{
-  guint key;
-
-  key = event->keyval;
-
-  switch (key) {
-  case GDK_KEY_Left:
-  case GDK_KEY_KP_Left:
-    move_cursor (-1, 0);
-    break;
-  case GDK_KEY_Right:
-  case GDK_KEY_KP_Right:
-    move_cursor (1, 0);
-    break;
-  case GDK_KEY_Up:
-  case GDK_KEY_KP_Up:
-    move_cursor (0, -1);
-    break;
-  case GDK_KEY_Down:
-  case GDK_KEY_KP_Down:
-    move_cursor (0, 1);
-    break;
-  case GDK_KEY_Home:
-  case GDK_KEY_KP_Home:
-    move_cursor (-999, 0);
-    break;
-  case GDK_KEY_End:
-  case GDK_KEY_KP_End:
-    move_cursor (999, 0);
-    break;
-  case GDK_KEY_Page_Up:
-  case GDK_KEY_KP_Page_Up:
-    move_cursor (0, -999);
-    break;
-  case GDK_KEY_Page_Down:
-  case GDK_KEY_KP_Page_Down:
-    move_cursor (0, 999);
-    break;
-
-  case GDK_KEY_space:
-  case GDK_KEY_Return:
-  case GDK_KEY_KP_Enter:
-    if (show_cursor)
-      cell_clicked (widget, cursor_x, cursor_y);
-    break;
-  }
-
-  return TRUE;
-}
-
-static void
-draw_grid (cairo_t *cr)
-{
-  GdkRGBA color;
-  guint w, h;
-  guint i;
-
-  w = gtk_widget_get_allocated_width(draw_area);
-  h = gtk_widget_get_allocated_height(draw_area);
-
-  gdk_rgba_parse (&color, "#525F6C");
-  gdk_cairo_set_source_rgba (cr, &color);
-  cairo_set_line_width (cr, 1.0);
-
-  for (i = boxsize; i < w; i = i + boxsize)
-  {
-    cairo_move_to (cr, i + 0.5, 0 + 0.5);
-    cairo_line_to (cr, i + 0.5, h + 0.5);
-  }
-
-  for (i = boxsize; i < h; i = i + boxsize)
-  {
-    cairo_move_to (cr, 0 + 0.5, i + 0.5);
-    cairo_line_to (cr, w + 0.5, i + 0.5);
-  }
-
-  cairo_rectangle (cr, 0.5, 0.5, w - 0.5, h - 0.5);
-  cairo_stroke (cr);
-}
-
-static gboolean
-field_draw_callback (GtkWidget * widget, cairo_t *cr)
-{
-  guint i, j, idx;
-  GdkRGBA cursorColor;
-
-  for (i = 0; i < vfieldsize; i++) {
-    for (j = 0; j < hfieldsize; j++) {
-      int phase, color;
-
-      idx = j + i * hfieldsize;
-
-      cairo_rectangle (cr, j * boxsize, i * boxsize, boxsize, boxsize);
-
-      if (field[idx].color != 0) {
-        phase = field[idx].phase;
-        color = field[idx].color - 1;
-
-        phase = ABS (ABS (3 - phase) - 3);
-
-        cairo_set_source_surface (cr, ball_surface,
-                                 (1.0 * j - phase) * boxsize,
-                                 (1.0 * i - color) * boxsize);
-      } else {
-        cairo_set_source_surface (cr, blank_surface, 1.0 * j * boxsize, 1.0 * i * boxsize);
-      }
-
-      cairo_fill (cr);
-    }
-  }
-
-  /* Cursor */
-  if (show_cursor) {
-    if (((backgnd.color.red + backgnd.color.green + backgnd.color.blue) / 3) > 0.5)
-      gdk_rgba_parse (&cursorColor, "#000000");
-    else
-      gdk_rgba_parse (&cursorColor, "#FFFFFF");
-
-    gdk_cairo_set_source_rgba (cr, &cursorColor);
-    cairo_set_line_width (cr, 1.0);
-    cairo_rectangle (cr,
-                     cursor_x * boxsize + 1.5, cursor_y * boxsize + 1.5,
-                     boxsize - 2.5, boxsize - 2.5);
-    cairo_stroke (cr);
-  }
-
-  draw_grid (cr);
-
-  return FALSE;
-}
-
-static int
-addscore (int num)
-{
-  gchar string[20];
-  int i = 0;
-  int retval;
-
-  while ((sctab[i].num != num) && (sctab[i].num != 0))
-    i++;
-  if (sctab[i].num == 0) {
-    num-=5;
-    retval = sctab[num%5].score + 72 * (num/5) + (num-5)*24 ;
-  } else
-    retval = sctab[i].score;
-
-  score += retval;
-  g_snprintf (string, 19, "%d", score);
-  gtk_label_set_text (GTK_LABEL (scorelabel), string);
-
-  return retval;
-}
-
-
-static void
-tag_list (int *list, int len)
-{
-  int i;
-
-  for (i = 0; i < len; i++)
-    field[list[i]].tag = 1;
-}
-
-static int
-find_lines (int num)
-{
-  int count = 1;
-  int subcount = 0;
-  int x = num % hfieldsize;
-  int y = num / hfieldsize;
-  int list[hfieldsize];
-
-  /* Horizontal */
-
-  x++;
-  while ((x <= hfieldsize - 1)
-         && (field[x + y * hfieldsize].color == field[num].color)) {
-    list[subcount] = x + y * hfieldsize;
-    subcount++;
-    x++;
-  }
-  x = num % hfieldsize - 1;
-  while ((x >= 0) && (field[x + y * hfieldsize].color == field[num].color)) {
-    list[subcount] = x + y * hfieldsize;
-    subcount++;
-    x--;
-  }
-  if (subcount >= 4) {
-    field[num].tag = 1;
-    tag_list (list, subcount);
-    count += subcount;
-  }
-  subcount = 0;
-
-  /* Vertical */
-
-  x = num % hfieldsize;
-  y++;
-  while ((y <= vfieldsize - 1)
-         && (field[x + y * hfieldsize].color == field[num].color)) {
-    list[subcount] = x + y * hfieldsize;
-    subcount++;
-    y++;
-  }
-  y = num / hfieldsize - 1;
-  while ((y >= 0) && (field[x + y * hfieldsize].color == field[num].color)) {
-    list[subcount] = x + y * hfieldsize;
-    subcount++;
-    y--;
-  }
-  if (subcount >= 4) {
-    field[num].tag = 1;
-    tag_list (list, subcount);
-    count += subcount;
-  }
-  subcount = 0;
-
-  /* Diagonal ++ */
-
-  x = num % hfieldsize + 1;
-  y = num / hfieldsize + 1;
-  while ((y <= vfieldsize - 1) && (x <= hfieldsize - 1)
-         && (field[x + y * hfieldsize].color == field[num].color)) {
-    list[subcount] = x + y * hfieldsize;
-    subcount++;
-    y++;
-    x++;
-  }
-  x = num % hfieldsize - 1;
-  y = num / hfieldsize - 1;
-  while ((y >= 0) && (x >= 0)
-         && (field[x + y * hfieldsize].color == field[num].color)) {
-    list[subcount] = x + y * hfieldsize;
-    subcount++;
-    y--;
-    x--;
-  }
-  if (subcount >= 4) {
-    field[num].tag = 1;
-    tag_list (list, subcount);
-    count += subcount;
-  }
-  subcount = 0;
-
-  /* Diagonal +- */
-
-  x = num % hfieldsize + 1;
-  y = num / hfieldsize - 1;
-  while ((y >= 0) && (x <= hfieldsize - 1)
-         && (field[x + y * hfieldsize].color == field[num].color)) {
-    list[subcount] = x + y * hfieldsize;
-    subcount++;
-    y--;
-    x++;
-  }
-  x = num % hfieldsize - 1;
-  y = num / hfieldsize + 1;
-  while ((y <= vfieldsize - 1) && (x >= 0)
-         && (field[x + y * hfieldsize].color == field[num].color)) {
-    list[subcount] = x + y * hfieldsize;
-    subcount++;
-    y++;
-    x--;
-  }
-  if (subcount >= 4) {
-    field[num].tag = 1;
-    tag_list (list, subcount);
-    count += subcount;
-  }
-
-  return count;
-}
-
-static void
-clear_tags (void)
-{
-  int i;
-
-  for (i = 0; i < hfieldsize * vfieldsize; i++)
-    field[i].tag = 0;
-}
-
-static int
-kill_tags (GtkWidget * widget)
-{
-  int i, j;
-
-  j = 0;
-  for (i = 0; i < hfieldsize * vfieldsize; i++) {
-    if (field[i].tag == 1) {
-      j++;
-      field[i].color = 0;
-      field[i].phase = 0;
-      field[i].active = 0;
-      draw_box (widget, i % hfieldsize, i / hfieldsize);
-    }
-  }
-
-  return j;
-}
-
-static gboolean
-check_goal (GtkWidget * w, int target)
-{
-  gboolean lines_cleared;
-  int count;
-
-  clear_tags ();
-
-  count = find_lines (target);
-  lines_cleared = count >= 5;
-
-  if (lines_cleared) {
-    kill_tags (w);
-    addscore (count);
-  }
-  reset_pathsearch ();
-
-  return lines_cleared;
-}
-
-gint
-animate (gpointer gp)
-{
-  GtkWidget *widget = GTK_WIDGET (gp);
-  int x, y;
-  int newactive = 0;
-
-  x = active % hfieldsize;
-  y = active / hfieldsize;
-
-  if (active == -1) {
-    animate_id = 0;
-    return FALSE;
-  }
-
-  if (inmove != 0) {
-    if ((x > 0)
-        && (field[active - 1].pathsearch == field[active].pathsearch + 1))
-      newactive = active - 1;
-    else if ((x < hfieldsize - 1)
-             && (field[active + 1].pathsearch ==
-                 field[active].pathsearch + 1))
-      newactive = active + 1;
-    else if ((y > 0)
-             && (field[active - hfieldsize].pathsearch ==
-                 field[active].pathsearch + 1))
-      newactive = active - hfieldsize;
-    else if ((y < vfieldsize - 1)
-             && (field[active + hfieldsize].pathsearch ==
-                 field[active].pathsearch + 1))
-      newactive = active + hfieldsize;
-    else {
-      set_inmove (0);
-    }
-    draw_box (widget, x, y);
-    x = newactive % hfieldsize;
-    y = newactive / hfieldsize;
-    field[newactive].phase = field[active].phase;
-    field[newactive].color = field[active].color;
-    field[active].phase = 0;
-    field[active].color = 0;
-    field[active].active = 0;
-    if (newactive == target) {
-      target = -1;
-      set_inmove (0);
-      active = -1;
-      field[newactive].phase = 0;
-      field[newactive].active = 0;
-      draw_box (widget, x, y);
-      reset_pathsearch ();
-      if (!check_goal (widget, newactive)) {
-        gboolean fullline;
-        int balls[npieces];
-        int spaces;
-
-        clear_tags ();
-        fullline = FALSE;
-        spaces = spaces_left ();
-        if (spaces > npieces)
-          spaces = npieces;
-        for (x = 0; x < spaces; x++) {
-          int tmp = init_new_balls (1, x);
-          draw_box (widget, tmp % hfieldsize, tmp / hfieldsize);
-          balls[x] = tmp;
-          fullline = (find_lines (balls[x]) >= 5) || fullline;
-        }
-        if (fullline)
-          addscore (kill_tags (widget));
-        if (check_gameover () == -1)
-          return FALSE;
-        init_preview ();
-        draw_preview ();
-      }
-      return TRUE;
-    }
-    field[newactive].active = 1;
-    active = newactive;
-  }
-
-  field[active].phase++;
-  if (field[active].phase >= 4)
-    field[active].phase = 0;
-  draw_box (widget, x, y);
-
-  return TRUE;
-}
-
-void
-game_top_ten_callback (GSimpleAction *action,
-                       GVariant *parameter,
-                       gpointer user_data)
-{
-  show_scores (0);
-}
-
-void
-game_about_callback (GSimpleAction *action,
-                     GVariant *parameter,
-                     gpointer user_data)
-{
-  const gchar *authors[] = { "Robert Szokovacs <szo appaloosacorp hu>",
-    "Szabolcs B\xc3\xa1n <shooby gnome hu>",
-    NULL
-  };
-
-  const gchar *documenters[] = { "Tiffany Antopolski",
-                                 "Lanka Rathnayaka",
-    NULL
-  };
-
-  gtk_show_about_dialog (GTK_WINDOW (app),
-                         "program-name", _("Five or More"),
-                         "version", VERSION,
-                         "comments", _("GNOME port of the once-popular Color Lines game"),
-                         "copyright",
-                         "Copyright © 1997–2008 Free Software Foundation, Inc.\n Copyright © 2013–2014 
Michael Catanzaro",
-                         "license-type", GTK_LICENSE_GPL_2_0,
-                         "authors", authors,
-                         "documenters", documenters,
-                         "translator-credits", _("translator-credits"),
-                         "logo-icon-name", "five-or-more",
-                         "website", "https://wiki.gnome.org/Apps/Five%20or%20more";,
-                         NULL);
-}
-
-static void
-set_backgnd_color (const gchar * str)
-{
-  if (!str)
-    str = g_strdup ("#000000");
-
-  if (str != backgnd.name) {
-    g_free (backgnd.name);
-    backgnd.name = g_strdup (str);
-  }
-
-  if (!gdk_rgba_parse (&backgnd.color, backgnd.name)) {
-    gdk_rgba_parse (&backgnd.color, "#000000");
-  }
-}
-
-static void
-set_sizes (gint size)
-{
-  hfieldsize = field_sizes[size][0];
-  vfieldsize = field_sizes[size][1];
-  ncolors = field_sizes[size][2];
-  npieces = field_sizes[size][3];
-  game_size = size;
-  games_scores_set_category (highscores, scorecats[size - 1].key);
-
-  g_settings_set_int (settings, KEY_SIZE, size);
-
-  if (gridframe)
-    games_grid_frame_set (GAMES_GRID_FRAME (gridframe),
-                          hfieldsize, vfieldsize);
-}
-
-static void
-load_theme (void)
-{
-  if (ball_preimage)
-    g_object_unref (ball_preimage);
-  ball_preimage = load_image (ball_filename);
-
-  refresh_pixmaps ();
-  refresh_preview_surfaces ();
-}
-
-static void
-conf_value_changed_cb (GSettings *settings, gchar *key)
-{
-  if (strcmp (key, KEY_BACKGROUND_COLOR) == 0) {
-    gchar *color;
-
-    color = g_settings_get_string (settings, KEY_BACKGROUND_COLOR);
-    if (color != NULL) {
-      set_backgnd_color (color);
-      g_free (color);
-    }
-  } else if (strcmp (key, KEY_BALL_THEME) == 0) {
-    gchar *theme_tmp = NULL;
-
-    theme_tmp = g_settings_get_string (settings, KEY_BALL_THEME);
-    if (theme_tmp) {
-      if (strcmp (theme_tmp, ball_filename) != 0) {
-        g_free (ball_filename);
-        ball_filename = theme_tmp;
-        load_theme ();
-        refresh_screen ();
-      } else
-        g_free (theme_tmp);
-    }
-    /* FIXME apply in the prefs dialog GUI */
-  } else if (strcmp (key, KEY_MOVE_TIMEOUT) == 0) {
-    gint timeout_tmp;
-
-    timeout_tmp = g_settings_get_int (settings, KEY_MOVE_TIMEOUT);
-    timeout_tmp = CLAMP (timeout_tmp, 1, 1000);
-    if (timeout_tmp != move_timeout)
-      move_timeout = timeout_tmp;
-
-  } else if (strcmp (key, KEY_SIZE) == 0) {
-    gint size_tmp;
-    size_tmp = g_settings_get_int (settings, KEY_SIZE);
-
-    if (size_tmp != game_size) {
-      set_sizes (size_tmp);
-      reset_game ();
-      start_game ();
-    }
-  }
-}
-
-static void
-bg_color_callback (GtkWidget * widget, gpointer data)
-{
-  GdkRGBA c;
-  char str[64];
-
-  gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (widget), &c);
-
-  g_snprintf (str, sizeof (str), "#%04x%04x%04x", (int) (c.red * 65535 + 0.5), (int) (c.green * 65535 + 
0.5), (int) (c.blue * 65535 + 0.5));
-
-  g_settings_set_string (settings, KEY_BACKGROUND_COLOR, str);
-
-  load_theme ();
-  refresh_screen ();
-}
-
-static void
-size_callback (GtkWidget * widget, gpointer data)
-{
-  GtkWidget *size_radio, *content_area, *label;
-
-  game_size = g_settings_get_int (settings, KEY_SIZE);
-  if (pref_dialog_done && game_size != GPOINTER_TO_INT (data) && !restart_game_dialog) {
-    GtkDialogFlags flags = GTK_DIALOG_DESTROY_WITH_PARENT;
-
-    restart_game_dialog = gtk_message_dialog_new (GTK_WINDOW (pref_dialog),
-                                                 GTK_MESSAGE_WARNING,
-                                                 flags,
-                                                 GTK_BUTTONS_NONE,
-                                                 _("Are you sure you want to restart the game?"));
-
-    gtk_dialog_add_buttons (GTK_DIALOG (restart_game_dialog),
-                            _("_Cancel"), GTK_RESPONSE_CANCEL,
-                            _("_Restart"), GTK_RESPONSE_OK,
-                            NULL);
-
-    gint result = gtk_dialog_run (GTK_DIALOG (restart_game_dialog));
-    gtk_widget_destroy (restart_game_dialog);
-
-    switch (result) {
-    case GTK_RESPONSE_OK:
-      g_settings_set_int (settings, KEY_SIZE, GPOINTER_TO_INT (data));
-      break;
-    case GTK_RESPONSE_CANCEL:
-      switch (game_size) {
-      case SMALL:
-       size_radio = size_radio_s;
-       break;
-      case MEDIUM:
-       size_radio = size_radio_m;
-       break;
-      case LARGE:
-       size_radio = size_radio_l;
-       break;
-      }
-      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (size_radio), TRUE);
-    }
-
-    restart_game_dialog = NULL;
-  }
-}
-
-static void
-set_selection (GtkWidget * widget, char *data)
-{
-  const gchar *entry;
-
-  entry = games_file_list_get_nth (theme_file_list,
-                                   gtk_combo_box_get_active (GTK_COMBO_BOX
-                                                             (widget)));
-  g_settings_set_string (settings, KEY_BALL_THEME, entry);
-}
-
-static GtkWidget *
-fill_menu (void)
-{
-  gchar *pixmap_dir;
-
-  if (theme_file_list)
-    g_object_unref (theme_file_list);
-
-  pixmap_dir = g_build_filename (DATA_DIRECTORY, "themes", NULL);
-  theme_file_list = games_file_list_new_images (pixmap_dir, NULL);
-  g_free (pixmap_dir);
-  games_file_list_transform_basename (theme_file_list);
-
-  return games_file_list_create_widget (theme_file_list, ball_filename,
-                                        GAMES_FILE_LIST_REMOVE_EXTENSION |
-                                        GAMES_FILE_LIST_REPLACE_UNDERSCORES);
-}
-
-static void
-set_fast_moves_callback (GtkWidget * widget, gpointer * data)
-{
-  gboolean is_on = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
-  gint timeout = is_on ? 10 : 100;
-  g_settings_set_int (settings, KEY_MOVE_TIMEOUT, timeout);
-}
-
-void
-pref_dialog_response (GtkDialog * dialog, gint response, gpointer data)
-{
-  gtk_widget_hide (GTK_WIDGET (dialog));
-}
-
-void
-game_props_callback (GSimpleAction *action,
-                     GVariant *parameter,
-                     gpointer user_data)
-{
-  gchar *ui_path;
-  GError *error = NULL;
-  GtkWidget *omenu;
-  GtkWidget *grid;
-  GtkWidget *color_button;
-  GtkWidget *size_radio;
-  GtkWidget *fast_moves_checkbutton;
-
-  if (!pref_dialog) {
-    ui_path = g_build_filename (DATA_DIRECTORY, "five-or-more-preferences.ui", NULL);
-    builder_preferences = gtk_builder_new ();
-    gtk_builder_add_from_file (builder_preferences, ui_path, &error);
-    g_free (ui_path);
-
-    if (error) {
-      g_critical ("Unable to load the user interface file: %s", error->message);
-      g_error_free (error);
-      g_assert_not_reached ();
-    }
-
-    pref_dialog = GTK_WIDGET (gtk_builder_get_object (builder_preferences, "preferences_dialog"));
-    g_signal_connect (pref_dialog, "response",
-                      G_CALLBACK (pref_dialog_response), NULL);
-    g_signal_connect (pref_dialog, "delete-event",
-                      G_CALLBACK (gtk_widget_hide), NULL);
-
-    grid = GTK_WIDGET (gtk_builder_get_object (builder_preferences, "grid1"));
-    omenu = fill_menu ();
-    gtk_widget_show_all (GTK_WIDGET (omenu));
-    gtk_grid_attach (GTK_GRID (grid), GTK_WIDGET (omenu), 1, 0, 1, 1);
-    g_signal_connect (omenu, "changed",
-                      G_CALLBACK (set_selection), NULL);
-
-    color_button = GTK_WIDGET (gtk_builder_get_object (builder_preferences, "colorbutton1"));
-    gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (color_button), &backgnd.color);
-    g_signal_connect (color_button, "color-set",
-                      G_CALLBACK (bg_color_callback), NULL);
-
-    size_radio = GTK_WIDGET (gtk_builder_get_object (builder_preferences, "radiobutton_small"));
-    size_radio_s = size_radio;
-    g_signal_connect (size_radio, "clicked",
-                      G_CALLBACK (size_callback), GINT_TO_POINTER (1));
-    if (game_size == SMALL)
-      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (size_radio), TRUE);
-
-    size_radio = GTK_WIDGET (gtk_builder_get_object (builder_preferences, "radiobutton_medium"));
-    size_radio_m = size_radio;
-    g_signal_connect (size_radio, "clicked",
-                      G_CALLBACK (size_callback), GINT_TO_POINTER (2));
-    if (game_size == MEDIUM)
-      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (size_radio), TRUE);
-
-    size_radio = GTK_WIDGET (gtk_builder_get_object (builder_preferences, "radiobutton_large"));
-    size_radio_l = size_radio;
-    g_signal_connect (size_radio, "clicked",
-                      G_CALLBACK (size_callback), GINT_TO_POINTER (3));
-    if (game_size == LARGE)
-      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (size_radio), TRUE);
-
-    fast_moves_checkbutton = GTK_WIDGET (gtk_builder_get_object (builder_preferences, 
"checkbutton_fast_moves"));
-    if (move_timeout == 10) {
-      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fast_moves_checkbutton), TRUE);
-    }
-
-    g_signal_connect (fast_moves_checkbutton, "clicked",
-                      G_CALLBACK (set_fast_moves_callback), NULL);
-
-    g_object_unref (G_OBJECT (builder_preferences));
-
-    pref_dialog_done = TRUE;
-    gtk_window_set_transient_for (GTK_WINDOW (pref_dialog), GTK_WINDOW (app));
-  }
-  gtk_dialog_run (GTK_DIALOG (pref_dialog));
-}
-
-void
-game_quit_callback (GSimpleAction *action,
-                    GVariant *parameter,
-                    gpointer user_data)
-{
-  g_application_quit (G_APPLICATION (user_data));
-}
-
-void
-game_help_callback (GSimpleAction *action,
-                    GVariant *parameter,
-                    gpointer user_data)
-{
-  GError *error = NULL;
-
-  gtk_show_uri (gtk_widget_get_screen (GTK_WIDGET (app)), "help:five-or-more", gtk_get_current_event_time 
(), &error);
-  if (error)
-    g_warning ("Failed to show help: %s", error->message);
-  g_clear_error (&error);
-}
-
-static int
-configure_event_callback (GtkWidget * widget, GdkEventConfigure * event)
-{
-  if (ball_surface)
-    cairo_surface_destroy(ball_surface);
-
-  if (blank_surface)
-    cairo_surface_destroy (blank_surface);
-
-  boxsize = (event->width - 1) / hfieldsize;
-  ball_surface = gdk_window_create_similar_surface (gtk_widget_get_window (draw_area),
-                                                    CAIRO_CONTENT_COLOR_ALPHA,
-                                                    boxsize * 4, boxsize * 7);
-  blank_surface = gdk_window_create_similar_surface (gtk_widget_get_window (draw_area),
-                                                     CAIRO_CONTENT_COLOR_ALPHA,
-                                                     boxsize, boxsize);
-  refresh_pixmaps ();
-
-  refresh_screen ();
-
-  return TRUE;
-}
-
-static void
-load_properties (void)
-{
-  gchar *buf;
-
-  ball_filename = g_settings_get_string (settings, KEY_BALL_THEME);
-
-  move_timeout = g_settings_get_int (settings, KEY_MOVE_TIMEOUT);
-  if (move_timeout <= 0)
-    move_timeout = 100;
-
-  buf = g_settings_get_string (settings, KEY_BACKGROUND_COLOR); /* FIXMEchpe? */
-  set_backgnd_color (buf);
-  g_free (buf);
-
-  load_theme ();
-}
-
-static void
-init_config (void)
-{
-  g_signal_connect (settings, "changed",
-                    G_CALLBACK (conf_value_changed_cb), NULL);
-
-  game_size = g_settings_get_int (settings, KEY_SIZE);
-  if (game_size == UNSET)
-    game_size = DEFAULT_GAME_SIZE;
-
-  game_size = CLAMP (game_size, SMALL, MAX_SIZE - 1);
-  set_sizes (game_size);
-}
-
-static gboolean
-window_size_allocate_cb (GtkWidget *widget, GdkRectangle *allocation)
-{
-  if (!window_is_maximized && !window_is_fullscreen)
-    gtk_window_get_size (GTK_WINDOW (widget), &window_width, &window_height);
-
-  return FALSE;
-}
-
-static gboolean
-window_state_event_cb (GtkWidget *widget, GdkEventWindowState *event)
-{
-  if ((event->changed_mask & GDK_WINDOW_STATE_MAXIMIZED) != 0)
-    window_is_maximized = (event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) != 0;
-  if ((event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) != 0)
-    window_is_fullscreen = (event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN) != 0;
-  return FALSE;
-}
-
-static void
-startup_cb (GApplication *application)
-{
-  gchar *ui_path;
-  GtkWidget *hbox;
-  GtkWidget *preview_hbox;
-  GtkWidget *new_game_button;
-  guint i;
-  GError *error = NULL;
-
-  GActionEntry app_actions[] = {
-    { "new-game", game_new_callback },
-    { "scores", game_top_ten_callback },
-    { "preferences", game_props_callback },
-    { "help", game_help_callback },
-    { "about", game_about_callback },
-    { "quit", game_quit_callback }
-  };
-
-  g_action_map_add_action_entries (G_ACTION_MAP (application),
-                                   app_actions, G_N_ELEMENTS (app_actions),
-                                   application);
-
-  gtk_application_add_accelerator (GTK_APPLICATION (application), "<Primary>N", "app.new-game", NULL);
-
-  settings = g_settings_new ("org.gnome.five-or-more");
-
-  highscores = games_scores_new ("five-or-more",
-                                 scorecats, G_N_ELEMENTS (scorecats),
-                                 "board size", NULL,
-                                 0 /* default category */,
-                                 GAMES_SCORES_STYLE_PLAIN_DESCENDING);
-
-  init_config ();
-
-  builder = gtk_builder_new ();
-
-  ui_path = g_build_filename (DATA_DIRECTORY, "menu.ui", NULL);
-  gtk_builder_add_from_file (builder, ui_path, &error);
-  g_free (ui_path);
-
-  if (error) {
-    g_critical ("Unable to load the application menu file: %s", error->message);
-    g_error_free (error);
-  } else {
-    gtk_application_set_app_menu (GTK_APPLICATION (application),
-                                  G_MENU_MODEL (gtk_builder_get_object (builder, "appmenu")));
-  }
-
-  ui_path = g_build_filename (DATA_DIRECTORY, "five-or-more.ui", NULL);
-  gtk_builder_add_from_file (builder, ui_path, &error);
-  g_free (ui_path);
-
-  if (error) {
-    g_critical ("Unable to load the user interface file: %s", error->message);
-    g_error_free (error);
-    g_assert_not_reached ();
-  }
-
-  app = GTK_WIDGET (gtk_builder_get_object (builder, "glines_window"));
-  gtk_window_set_icon_name (GTK_WINDOW (app), "five-or-more");
-  g_signal_connect (GTK_WINDOW (app), "size-allocate", G_CALLBACK (window_size_allocate_cb), NULL);
-  g_signal_connect (GTK_WINDOW (app), "window-state-event", G_CALLBACK (window_state_event_cb), NULL);
-  gtk_window_set_default_size (GTK_WINDOW (app), g_settings_get_int (settings, "window-width"), 
g_settings_get_int (settings, "window-height"));
-  if (g_settings_get_boolean (settings, "window-is-maximized"))
-    gtk_window_maximize (GTK_WINDOW (app));
-  gtk_container_set_border_width (GTK_CONTAINER (app), 20);
-  gtk_application_add_window (GTK_APPLICATION (application), GTK_WINDOW (app));
-
-  headerbar = GTK_WIDGET (gtk_builder_get_object (builder, "headerbar"));
-
-  preview_hbox = GTK_WIDGET (gtk_builder_get_object (builder, "preview_hbox"));
-
-  for (i = 0; i < MAXNPIECES; i++) {
-    preview_images[i] = GTK_IMAGE (gtk_image_new ());
-    gtk_box_pack_start (GTK_BOX (preview_hbox), GTK_WIDGET (preview_images[i]), FALSE, FALSE, 0);
-    gtk_widget_realize (GTK_WIDGET (preview_images[i]));
-  }
-
-  scorelabel = GTK_WIDGET (gtk_builder_get_object (builder, "scorelabel"));
-
-  hbox = GTK_WIDGET (gtk_builder_get_object (builder, "hbox"));
-  draw_area = gtk_drawing_area_new ();
-  gtk_widget_set_size_request (draw_area, 300, 300);
-  g_signal_connect (draw_area, "button-press-event",
-                    G_CALLBACK (button_press_event), NULL);
-  g_signal_connect (draw_area, "key-press-event",
-                    G_CALLBACK (key_press_event), NULL);
-  g_signal_connect (draw_area, "configure-event",
-                    G_CALLBACK (configure_event_callback), NULL);
-  g_signal_connect (draw_area, "draw",
-                    G_CALLBACK (field_draw_callback), NULL);
-  gridframe = games_grid_frame_new (hfieldsize, vfieldsize);
-  games_grid_frame_set_padding (GAMES_GRID_FRAME (gridframe), 1, 1);
-  gtk_container_add (GTK_CONTAINER (gridframe), draw_area);
-  gtk_box_pack_start (GTK_BOX (hbox), gridframe, TRUE, TRUE, 0);
-
-  gtk_widget_set_events (draw_area,
-                         gtk_widget_get_events (draw_area) |
-                         GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK);
-
-  gtk_widget_set_can_focus (draw_area, TRUE);
-  gtk_widget_grab_focus (draw_area);
-
-  new_game_button = GTK_WIDGET (gtk_builder_get_object (builder, "new_game_button"));
-
-  load_properties ();
-
-  gtk_builder_connect_signals (builder, NULL);
-
-  g_object_unref (G_OBJECT (builder));
-}
-
-static void
-activate_cb (GApplication *application)
-{
-  reset_game ();
-  gtk_widget_show_all (app);
-  start_game ();
-}
-
-static void
-shutdown_cb (GApplication *application)
-{
-  int i = 0;
-
-  for (i = 0; i < G_N_ELEMENTS (preview_images); i++)
-    if (preview_pixbufs[i])
-      g_object_unref (preview_pixbufs[i]);
-
-  g_clear_object (&ball_preimage);
-  g_object_unref (highscores);
-
-  g_settings_set_int (settings, "window-width", window_width);
-  g_settings_set_int (settings, "window-height", window_height);
-  g_settings_set_boolean (settings, "window-is-maximized", window_is_maximized);
-}
+#include "game-area.h"
+#include "five-or-more-app.h"
 
 int
 main (int argc, char *argv[])
@@ -1706,8 +52,9 @@ main (int argc, char *argv[])
   textdomain (GETTEXT_PACKAGE);
 
   games_scores_startup ();
+  GRand **rgen  = get_rgen();
 
-  rgen = g_rand_new ();
+  *rgen = g_rand_new ();
 
   context = g_option_context_new (NULL);
   g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
@@ -1721,14 +68,13 @@ main (int argc, char *argv[])
     exit (1);
   }
 
-  g_set_application_name (_("Five or More"));
+  g_set_application_name (_("Five Or More"));
 
   gtk_window_set_default_icon_name ("five-or-more");
 
   application = gtk_application_new ("org.gnome.five-or-more", G_APPLICATION_FLAGS_NONE);
-  g_signal_connect (application, "startup", G_CALLBACK (startup_cb), NULL);
-  g_signal_connect (application, "activate", G_CALLBACK (activate_cb), NULL);
-  g_signal_connect (application, "shutdown", G_CALLBACK (shutdown_cb), NULL);
+  //defined in header
+  set_application_callbacks(application);
 
   status = g_application_run (G_APPLICATION (application), argc, argv);
 
diff --git a/src/game-area.c b/src/game-area.c
new file mode 100644
index 0000000..7a3043b
--- /dev/null
+++ b/src/game-area.c
@@ -0,0 +1,1057 @@
+/* -*- mode:C; indent-tabs-mode:t; tab-width:8; c-basic-offset:8; -*- */
+
+/*
+ * Color lines for GNOME
+ * Copyright © 1999 Free Software Foundation
+ * Authors: Robert Szokovacs <szo appaloosacorp hu>
+ *          Szabolcs Ban <shooby gnome hu>
+ *          Karuna Grewal <karunagrewal98 gmail com>
+ * Copyright © 2007 Christian Persch
+ *
+ * This game 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, 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, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <locale.h>
+#include <math.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gdk/gdkkeysyms.h>
+
+#include "games-gridframe.h"
+#include "game-area.h"
+#include "five-or-more-app.h"
+#include "balls-preview.h"
+
+#define MAXFIELDSIZE 30
+#define KEY_SIZE              "size"
+static GRand *rgen;
+static int inmove = 0;
+static int active = -1;
+static int target = -1;
+
+static int animate_id = 0;
+
+static gboolean show_cursor = FALSE;
+static int cursor_x = MAXFIELDSIZE / 2;
+static int cursor_y = MAXFIELDSIZE / 2;
+static field_props field[MAXFIELDSIZE * MAXFIELDSIZE];
+static gint hfieldsize;
+static gint vfieldsize;
+static int boxsize;
+static gint ncolors;
+
+static gint npieces;
+/* The tile images with balls rendered on them. */
+static cairo_surface_t *ball_surface = NULL;
+/* A cairo_surface_t of a blank tile. */
+static cairo_surface_t *blank_surface = NULL;
+/* Pre-rendering image data prepared from file. */
+static GamesPreimage *ball_preimage = NULL;
+
+enum {
+  UNSET = 0,
+  SMALL = 1,
+  MEDIUM,
+  LARGE,
+  MAX_SIZE,
+};
+
+/* Keep these in sync with the enum above. */
+static const gint field_sizes[MAX_SIZE][4] = {
+  {-1, -1, -1, -1}, /* This is a dummy entry. */
+  {7, 7, 5, 3},     /* SMALL */
+  {9, 9, 7, 3},     /* MEDIUM */
+  {20, 15, 7, 7}    /* LARGE */
+};
+
+static scoretable sctab[] =
+  { {5, 10}, {6, 12}, {7, 18}, {8, 28}, {9, 42}, {10, 82}, {11, 108}, {12,
+                                                                       138},
+  {13, 172}, {14, 210}, {0, 0} };
+
+static gchar *warning_message = NULL;
+static GtkWidget *draw_area;
+
+void
+set_sizes (gint size)
+{
+  hfieldsize = field_sizes[size][0];
+  vfieldsize = field_sizes[size][1];
+  ncolors = field_sizes[size][2];
+  npieces = field_sizes[size][3];
+  gint *game_size = get_game_size();
+  *game_size = size;
+  GamesScoresCategory *scorecats = get_scorecats();
+  games_scores_set_category (get_highscores(), scorecats[size - 1].key);
+
+  g_settings_set_int (*(get_settings()), KEY_SIZE, size);
+  GtkWidget *gridframe = get_gridframe();
+  if (gridframe)
+    games_grid_frame_set (GAMES_GRID_FRAME (gridframe),
+                          hfieldsize, vfieldsize);
+}
+
+gint
+get_hfieldsize()
+{
+  return hfieldsize;
+}
+
+gint
+get_vfieldsize()
+{
+  return vfieldsize;
+}
+
+gint *
+get_active_status()
+{
+  return &active;
+}
+
+gint *
+get_target_status()
+{
+  return &target;
+}
+
+gint *
+get_inmove_status()
+{
+  return &inmove;
+}
+
+gint
+get_ncolors()
+{
+  return ncolors;
+}
+
+GRand **
+get_rgen()
+{
+  return &rgen;
+}
+
+GamesPreimage *
+get_ball_preimage()
+{
+  return ball_preimage;
+}
+
+gint
+get_npieces()
+{
+  return npieces;
+}
+
+int
+init_new_balls (int num, int prev)
+{
+  int i, j = -1;
+  gfloat num_boxes = hfieldsize * vfieldsize;
+  for (i = 0; i < num;) {
+    j = g_rand_int_range (rgen, 0, num_boxes);
+    if (field[j].color == 0) {
+      field[j].color = (prev == -1) ?
+        g_rand_int_range (rgen, 1, ncolors + 1) : get_preview()[prev];
+      i++;
+    }
+  }
+  return j;
+}
+
+void
+reset_game (void)
+{
+  int i;
+
+  for (i = 0; i < hfieldsize * vfieldsize; i++) {
+    field[i].color = 0;
+    field[i].phase = 0;
+    field[i].active = 0;
+    field[i].pathsearch = -1;
+  }
+  update_score(0);
+  init_preview ();
+  init_new_balls (npieces, -1);
+}
+
+static void
+fix_route (int num, int pos)
+{
+  int i;
+
+  for (i = 0; i < hfieldsize * vfieldsize; i++)
+    if ((i != pos) && (field[i].pathsearch == num))
+      field[i].pathsearch = -1;
+  if (num < 2)
+    return;
+  if ((pos / hfieldsize > 0)
+      && (field[pos - hfieldsize].pathsearch == num - 1))
+    fix_route (num - 1, pos - hfieldsize);
+  if ((pos % hfieldsize > 0) && (field[pos - 1].pathsearch == num - 1))
+    fix_route (num - 1, pos - 1);
+  if ((pos / hfieldsize < vfieldsize - 1)
+      && (field[pos + hfieldsize].pathsearch == num - 1))
+    fix_route (num - 1, pos + hfieldsize);
+  if ((pos % hfieldsize < hfieldsize - 1)
+      && (field[pos + 1].pathsearch == num - 1))
+    fix_route (num - 1, pos + 1);
+}
+
+static int
+route (int num)
+{
+  int i;
+  int flag = 0;
+
+  if (field[target].pathsearch == num)
+    return 1;
+  for (i = 0; i < hfieldsize * vfieldsize; i++) {
+    if (field[i].pathsearch == num) {
+      flag = 1;
+      if ((i / hfieldsize > 0) && (field[i - hfieldsize].pathsearch == -1)
+          && (field[i - hfieldsize].color == 0))
+        field[i - hfieldsize].pathsearch = num + 1;
+      if ((i / hfieldsize < vfieldsize - 1)
+          && (field[i + hfieldsize].pathsearch == -1)
+          && (field[i + hfieldsize].color == 0))
+        field[i + hfieldsize].pathsearch = num + 1;
+      if ((i % hfieldsize > 0) && (field[i - 1].pathsearch == -1)
+          && (field[i - 1].color == 0))
+        field[i - 1].pathsearch = num + 1;
+      if ((i % hfieldsize < hfieldsize - 1) && (field[i + 1].pathsearch == -1)
+          && (field[i + 1].color == 0)) {
+        field[i + 1].pathsearch = num + 1;
+      }
+    }
+  }
+  if (flag == 0)
+    return 0;
+  return 2;
+}
+
+int
+find_route (void)
+{
+  int i = 0;
+  int j = 0;
+
+  field[active].pathsearch = i;
+  while ((j = route (i))) {
+    if (j == 1) {
+      fix_route (i, target);
+      return 1;
+    }
+    i++;
+  }
+  return 0;
+}
+
+
+static void
+reset_pathsearch (void)
+{
+  int i;
+
+  for (i = 0; i < hfieldsize * vfieldsize; i++)
+    field[i].pathsearch = -1;
+}
+
+void
+draw_box (GtkWidget * widget, int x, int y)
+{
+  gtk_widget_queue_draw_area (widget, x * boxsize, y * boxsize,
+                              boxsize, boxsize);
+}
+
+
+static void
+deactivate (GtkWidget * widget, int x, int y)
+{
+  field[active].active = 0;
+  field[active].phase = 0;
+  draw_box (widget, x, y);
+  active = -1;
+}
+
+static int
+spaces_left (void)
+{
+  int i, j;
+
+  j = 0;
+
+  for (i = 0; i < hfieldsize * vfieldsize; i++) {
+    if (field[i].color == 0)
+      j++;
+  }
+
+  return j;
+}
+
+static int
+check_gameover (void)
+{
+  if (spaces_left () > 0)
+    return 1;
+  game_over ();
+  return -1;
+}
+
+
+static int
+addscore (int num)
+{
+  gchar string[20];
+  int i = 0;
+  int retval;
+
+  while ((sctab[i].num != num) && (sctab[i].num != 0))
+    i++;
+  if (sctab[i].num == 0) {
+    num-=5;
+    retval = sctab[num%5].score + 72 * (num/5) + (num-5)*24 ;
+  } else
+    retval = sctab[i].score;
+  update_score(retval);
+
+  return retval;
+}
+
+
+static void
+tag_list (int *list, int len)
+{
+  int i;
+
+  for (i = 0; i < len; i++)
+    field[list[i]].tag = 1;
+}
+
+static int
+find_lines (int num)
+{
+  int count = 1;
+  int subcount = 0;
+  int x = num % hfieldsize;
+  int y = num / hfieldsize;
+  int list[hfieldsize];
+
+  /* Horizontal */
+
+  x++;
+  while ((x <= hfieldsize - 1)
+         && (field[x + y * hfieldsize].color == field[num].color)) {
+    list[subcount] = x + y * hfieldsize;
+    subcount++;
+    x++;
+  }
+  x = num % hfieldsize - 1;
+  while ((x >= 0) && (field[x + y * hfieldsize].color == field[num].color)) {
+    list[subcount] = x + y * hfieldsize;
+    subcount++;
+    x--;
+  }
+  if (subcount >= 4) {
+    field[num].tag = 1;
+    tag_list (list, subcount);
+    count += subcount;
+  }
+  subcount = 0;
+
+  /* Vertical */
+
+  x = num % hfieldsize;
+  y++;
+  while ((y <= vfieldsize - 1)
+         && (field[x + y * hfieldsize].color == field[num].color)) {
+    list[subcount] = x + y * hfieldsize;
+    subcount++;
+    y++;
+  }
+  y = num / hfieldsize - 1;
+  while ((y >= 0) && (field[x + y * hfieldsize].color == field[num].color)) {
+    list[subcount] = x + y * hfieldsize;
+    subcount++;
+    y--;
+  }
+  if (subcount >= 4) {
+    field[num].tag = 1;
+    tag_list (list, subcount);
+    count += subcount;
+  }
+  subcount = 0;
+
+  /* Diagonal ++ */
+
+  x = num % hfieldsize + 1;
+  y = num / hfieldsize + 1;
+  while ((y <= vfieldsize - 1) && (x <= hfieldsize - 1)
+         && (field[x + y * hfieldsize].color == field[num].color)) {
+    list[subcount] = x + y * hfieldsize;
+    subcount++;
+    y++;
+    x++;
+  }
+  x = num % hfieldsize - 1;
+  y = num / hfieldsize - 1;
+  while ((y >= 0) && (x >= 0)
+         && (field[x + y * hfieldsize].color == field[num].color)) {
+    list[subcount] = x + y * hfieldsize;
+    subcount++;
+    y--;
+    x--;
+  }
+  if (subcount >= 4) {
+    field[num].tag = 1;
+    tag_list (list, subcount);
+    count += subcount;
+  }
+  subcount = 0;
+
+  /* Diagonal +- */
+
+  x = num % hfieldsize + 1;
+  y = num / hfieldsize - 1;
+  while ((y >= 0) && (x <= hfieldsize - 1)
+         && (field[x + y * hfieldsize].color == field[num].color)) {
+    list[subcount] = x + y * hfieldsize;
+    subcount++;
+    y--;
+    x++;
+  }
+  x = num % hfieldsize - 1;
+  y = num / hfieldsize + 1;
+  while ((y <= vfieldsize - 1) && (x >= 0)
+         && (field[x + y * hfieldsize].color == field[num].color)) {
+    list[subcount] = x + y * hfieldsize;
+    subcount++;
+    y++;
+    x--;
+  }
+  if (subcount >= 4) {
+    field[num].tag = 1;
+    tag_list (list, subcount);
+    count += subcount;
+  }
+
+  return count;
+}
+
+
+static void
+clear_tags (void)
+{
+  int i;
+
+  for (i = 0; i < hfieldsize * vfieldsize; i++)
+    field[i].tag = 0;
+}
+
+static int
+kill_tags (GtkWidget * widget)
+{
+  int i, j;
+
+  j = 0;
+  for (i = 0; i < hfieldsize * vfieldsize; i++) {
+    if (field[i].tag == 1) {
+      j++;
+      field[i].color = 0;
+      field[i].phase = 0;
+      field[i].active = 0;
+      draw_box (widget, i % hfieldsize, i / hfieldsize);
+    }
+  }
+
+  return j;
+}
+
+static gboolean
+check_goal (GtkWidget * w, int target)
+{
+  gboolean lines_cleared;
+  int count;
+
+  clear_tags ();
+
+  count = find_lines (target);
+  lines_cleared = count >= 5;
+
+  if (lines_cleared) {
+    kill_tags (w);
+    addscore (count);
+  }
+  reset_pathsearch ();
+
+  return lines_cleared;
+}
+
+gint
+animate (gpointer gp)
+{
+  GtkWidget *widget = GTK_WIDGET (gp);
+  int x, y;
+  int newactive = 0;
+
+  x = active % hfieldsize;
+  y = active / hfieldsize;
+
+  if (active == -1) {
+    animate_id = 0;
+    return FALSE;
+  }
+
+  if (inmove != 0) {
+    if ((x > 0)
+        && (field[active - 1].pathsearch == field[active].pathsearch + 1))
+      newactive = active - 1;
+    else if ((x < hfieldsize - 1)
+             && (field[active + 1].pathsearch ==
+                 field[active].pathsearch + 1))
+      newactive = active + 1;
+    else if ((y > 0)
+             && (field[active - hfieldsize].pathsearch ==
+                 field[active].pathsearch + 1))
+      newactive = active - hfieldsize;
+    else if ((y < vfieldsize - 1)
+             && (field[active + hfieldsize].pathsearch ==
+                 field[active].pathsearch + 1))
+      newactive = active + hfieldsize;
+    else {
+      set_inmove (0);
+    }
+    draw_box (widget, x, y);
+    x = newactive % hfieldsize;
+    y = newactive / hfieldsize;
+    field[newactive].phase = field[active].phase;
+    field[newactive].color = field[active].color;
+    field[active].phase = 0;
+    field[active].color = 0;
+    field[active].active = 0;
+    if (newactive == target) {
+      target = -1;
+      set_inmove (0);
+      active = -1;
+      field[newactive].phase = 0;
+      field[newactive].active = 0;
+      draw_box (widget, x, y);
+      reset_pathsearch ();
+      if (!check_goal (widget, newactive)) {
+        gboolean fullline;
+        int balls[npieces];
+        int spaces;
+
+        clear_tags ();
+        fullline = FALSE;
+        spaces = spaces_left ();
+        if (spaces > npieces)
+          spaces = npieces;
+        for (x = 0; x < spaces; x++) {
+          int tmp = init_new_balls (1, x);
+          draw_box (widget, tmp % hfieldsize, tmp / hfieldsize);
+          balls[x] = tmp;
+          fullline = (find_lines (balls[x]) >= 5) || fullline;
+        }
+        if (fullline)
+          addscore (kill_tags (widget));
+        if (check_gameover () == -1)
+          return FALSE;
+        init_preview ();
+        draw_preview ();
+      }
+      return TRUE;
+    }
+    field[newactive].active = 1;
+    active = newactive;
+  }
+
+  field[active].phase++;
+  if (field[active].phase >= 4)
+    field[active].phase = 0;
+  draw_box (widget, x, y);
+
+  return TRUE;
+}
+
+static void
+start_animation (void)
+{
+  int ms;
+
+  ms = (inmove ? get_move_timeout() : 100);
+  if (animate_id == 0)
+    animate_id = g_timeout_add (ms, animate, draw_area);
+}
+
+void
+set_inmove (int i)
+{
+  if (inmove != i) {
+    inmove = i;
+    if (animate_id)
+      g_source_remove (animate_id);
+    animate_id = 0;
+    start_animation ();
+  }
+}
+
+static void
+cell_clicked (GtkWidget * widget, int fx, int fy)
+{
+  int x, y;
+
+  set_status_message (NULL);
+  if (field[fx + fy * hfieldsize].color == 0) {
+    /* Clicked on an empty field */
+
+    if ((active != -1) && (inmove != 1)) {
+      /* We have an active ball, and it's not
+       * already in move. Therefore we should begin
+       * the moving sequence */
+
+      target = fx + fy * hfieldsize;
+      if (find_route ()) {
+        /* We found a route to the new position */
+
+        set_inmove (1);
+      } else {
+        /* Can't move there! */
+        set_status_message (_("You can’t move there!"));
+        reset_pathsearch ();
+        target = -1;
+      }
+    }
+  } else {
+    /* Clicked on a ball */
+
+    if ((fx + fy * hfieldsize) == active) {
+      /* It's active, so let's deactivate it! */
+
+      deactivate (widget, fx, fy);
+    } else {
+      /* It's not active, so let's activate it! */
+
+      if (active != -1) {
+        /* There is an other active ball, we should deactivate it first! */
+
+        x = active % hfieldsize;
+        y = active / hfieldsize;
+        deactivate (widget, x, y);
+      }
+
+      active = fx + fy * hfieldsize;
+      field[active].active = 1;
+      start_animation();
+    }
+  }
+
+}
+
+static gint
+button_press_event (GtkWidget * widget, GdkEvent * event)
+{
+  int x, y;
+  int fx, fy;
+
+  if (inmove)
+    return TRUE;
+
+  /* Ignore the 2BUTTON and 3BUTTON events. */
+  if (event->type != GDK_BUTTON_PRESS)
+    return TRUE;
+
+  if (show_cursor) {
+    show_cursor = FALSE;
+    draw_box (draw_area, cursor_x, cursor_y);//put in header
+  }
+
+  fx = event->button.x / boxsize;
+  fy = event->button.y / boxsize;
+
+  /* If we click on the outer border pixels, the previous calculation
+   * will be wrong and we must correct. */
+  fx = CLAMP (fx, 0, hfieldsize - 1);
+  fy = CLAMP (fy, 0, vfieldsize - 1);
+
+  cursor_x = fx;
+  cursor_y = fy;
+
+  cell_clicked (widget, fx, fy);
+
+  return TRUE;
+}
+
+static void
+move_cursor (int dx, int dy)
+{
+  int old_x = cursor_x;
+  int old_y = cursor_y;
+
+  if (!show_cursor) {
+    show_cursor = TRUE;
+    draw_box (draw_area, cursor_x, cursor_y);
+  }
+
+  cursor_x = cursor_x + dx;
+  if (cursor_x < 0)
+    cursor_x = 0;
+  if (cursor_x >= hfieldsize)
+    cursor_x = hfieldsize - 1;
+  cursor_y = cursor_y + dy;
+  if (cursor_y < 0)
+    cursor_y = 0;
+  if (cursor_y >= vfieldsize)
+    cursor_y = vfieldsize - 1;
+
+  if (cursor_x == old_x && cursor_y == old_y)
+    return;
+
+  draw_box (draw_area, old_x, old_y);
+  draw_box (draw_area, cursor_x, cursor_y);
+}
+
+static gboolean
+key_press_event (GtkWidget * widget, GdkEventKey * event, void *d)
+{
+  guint key;
+
+  key = event->keyval;
+
+  switch (key) {
+  case GDK_KEY_Left:
+  case GDK_KEY_KP_Left:
+    move_cursor (-1, 0);
+    break;
+  case GDK_KEY_Right:
+  case GDK_KEY_KP_Right:
+    move_cursor (1, 0);
+    break;
+  case GDK_KEY_Up:
+  case GDK_KEY_KP_Up:
+    move_cursor (0, -1);
+    break;
+  case GDK_KEY_Down:
+  case GDK_KEY_KP_Down:
+    move_cursor (0, 1);
+    break;
+  case GDK_KEY_Home:
+  case GDK_KEY_KP_Home:
+    move_cursor (-999, 0);
+    break;
+  case GDK_KEY_End:
+  case GDK_KEY_KP_End:
+    move_cursor (999, 0);
+    break;
+  case GDK_KEY_Page_Up:
+  case GDK_KEY_KP_Page_Up:
+    move_cursor (0, -999);
+    break;
+  case GDK_KEY_Page_Down:
+  case GDK_KEY_KP_Page_Down:
+    move_cursor (0, 999);
+    break;
+
+  case GDK_KEY_space:
+  case GDK_KEY_Return:
+  case GDK_KEY_KP_Enter:
+    if (show_cursor)
+      cell_clicked (widget, cursor_x, cursor_y);
+    break;
+  }
+
+  return TRUE;
+}
+
+static void
+draw_grid (cairo_t *cr)
+{
+  GdkRGBA color;
+  guint w, h;
+  guint i;
+  w = gtk_widget_get_allocated_width(draw_area);
+  h = gtk_widget_get_allocated_height(draw_area);
+
+  gdk_rgba_parse (&color, "#525F6C");
+  gdk_cairo_set_source_rgba (cr, &color);
+  cairo_set_line_width (cr, 1.0);
+
+  for (i = boxsize; i < w; i = i + boxsize)
+  {
+    cairo_move_to (cr, i + 0.5, 0 + 0.5);
+    cairo_line_to (cr, i + 0.5, h + 0.5);
+  }
+
+  for (i = boxsize; i < h; i = i + boxsize)
+  {
+    cairo_move_to (cr, 0 + 0.5, i + 0.5);
+    cairo_line_to (cr, w + 0.5, i + 0.5);
+  }
+
+  cairo_rectangle (cr, 0.5, 0.5, w - 0.5, h - 0.5);
+  cairo_stroke (cr);
+}
+
+static GamesPreimage *
+load_image (gchar * fname)
+{
+  GamesPreimage *preimage;
+  gchar *path;
+  GError *error = NULL;
+
+  path = g_build_filename (DATA_DIRECTORY, "themes", fname, NULL);
+  if (!g_file_test (path, G_FILE_TEST_EXISTS)) {
+    warning_message = g_strdup_printf (_("Unable to locate file:\n%s\n\n"
+                                         "The default theme will be loaded instead."),
+                                       fname);
+
+    path = g_build_filename (DATA_DIRECTORY, "themes", "balls.svg", NULL);
+    if (!g_file_test (path, G_FILE_TEST_EXISTS)) {
+      g_free (warning_message);
+      warning_message = g_strdup_printf (_("Unable to locate file:\n%s\n\n"
+                                           "Please check that Five or More is installed correctly."),
+                                         fname);
+    }
+  }
+
+  preimage = games_preimage_new_from_file (path, &error);
+  g_free (path);
+
+  if (error) {
+    warning_message = g_strdup (error->message);
+    g_error_free (error);
+  }
+
+  return preimage;
+}
+
+static void
+show_image_warning (gchar * message)
+{
+  GtkWidget *dialog;
+  GtkWidget *button;
+
+  dialog = gtk_message_dialog_new (NULL,
+                                   GTK_DIALOG_MODAL,
+                                   GTK_MESSAGE_WARNING,
+                                   GTK_BUTTONS_CLOSE,
+                                   "%s",_("Could not load theme"));
+
+  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+                                            "%s", message);
+
+  button = gtk_dialog_add_button (GTK_DIALOG (dialog),
+                                  _("Preferences"), GTK_RESPONSE_ACCEPT);
+
+  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
+
+  g_signal_connect (button, "clicked", G_CALLBACK (game_props_callback),
+                    NULL);
+
+  gtk_dialog_run (GTK_DIALOG (dialog));
+  gtk_widget_destroy (dialog);
+}
+
+void
+refresh_pixmaps (void)
+{
+  cairo_t *cr, *cr_blank;
+  GdkPixbuf *ball_pixbuf = NULL;
+  background backgnd = get_backgnd();
+  /* Since we get called both by configure and after loading an image.
+   * it is possible the pixmaps aren't initialised. If they aren't
+   * we don't do anything. */
+  if (!ball_surface)
+    return;
+
+  if (!boxsize)
+    return;
+
+  if (ball_preimage) {
+    ball_pixbuf = games_preimage_render (ball_preimage, 4 * boxsize,
+                                         7 * boxsize);
+
+    /* Handle rendering problems. */
+    if (!ball_pixbuf) {
+      g_object_unref (ball_preimage);
+      ball_preimage = NULL;
+
+      if (!warning_message) {
+        warning_message = g_strdup ("The selected theme failed to render.\n\n"
+                                    "Please check that Five or More is installed correctly.");
+      }
+    }
+  }
+
+  if (!ball_pixbuf) {
+    ball_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
+                                  4 * boxsize, 7 * boxsize);
+    gdk_pixbuf_fill (ball_pixbuf, 0x00000000);
+  }
+
+  if (warning_message)
+    show_image_warning (warning_message);
+  g_free (warning_message);
+  warning_message = NULL;
+
+  cr = cairo_create (ball_surface);
+  gdk_cairo_set_source_rgba (cr, &backgnd.color);
+
+  cairo_rectangle (cr, 0, 0, boxsize * 4, boxsize * 7);
+  cairo_fill (cr);
+
+  gdk_cairo_set_source_pixbuf (cr, ball_pixbuf, 0, 0);
+  cairo_mask (cr, cairo_get_source (cr));
+  g_object_unref (ball_pixbuf);
+
+  cairo_destroy (cr);
+
+  cr_blank = cairo_create (blank_surface);
+  gdk_cairo_set_source_rgba (cr_blank, &backgnd.color);
+
+  cairo_rectangle (cr_blank, 0, 0, boxsize, boxsize);
+  cairo_fill (cr_blank);
+
+  cairo_destroy (cr_blank);
+}
+
+static void
+draw_all_balls (GtkWidget * widget)
+{
+  gdk_window_invalidate_rect (gtk_widget_get_window (widget), NULL, FALSE);
+}
+
+void
+refresh_screen (void)
+{
+  draw_all_balls (draw_area);
+  draw_preview ();
+}
+
+static int
+configure_event_callback (GtkWidget * widget, GdkEventConfigure * event)
+{
+  if (ball_surface)
+    cairo_surface_destroy(ball_surface);
+
+  if (blank_surface)
+    cairo_surface_destroy (blank_surface);
+
+  boxsize = (event->width - 1) / hfieldsize;
+  ball_surface = gdk_window_create_similar_surface (gtk_widget_get_window (draw_area),
+                                                    CAIRO_CONTENT_COLOR_ALPHA,
+                                                    boxsize * 4, boxsize * 7);
+  blank_surface = gdk_window_create_similar_surface (gtk_widget_get_window (draw_area),
+                                                     CAIRO_CONTENT_COLOR_ALPHA,
+                                                     boxsize, boxsize);
+  refresh_pixmaps ();
+
+  refresh_screen ();
+
+  return TRUE;
+}
+
+void
+load_theme (void)
+{
+  if (ball_preimage)
+    g_object_unref (ball_preimage);
+  char *ball_filename = get_ball_filename();
+  ball_preimage = load_image (ball_filename);
+
+  refresh_pixmaps ();
+  refresh_preview_surfaces ();
+}
+
+static gboolean
+field_draw_callback (GtkWidget * widget, cairo_t *cr)
+{
+  guint i, j, idx;
+  GdkRGBA cursorColor;
+  background backgnd = get_backgnd();
+
+  for (i = 0; i < vfieldsize; i++) {
+    for (j = 0; j < hfieldsize; j++) {
+      int phase, color;
+
+      idx = j + i * hfieldsize;
+
+      cairo_rectangle (cr, j * boxsize, i * boxsize, boxsize, boxsize);
+
+      if (field[idx].color != 0) {
+        phase = field[idx].phase;
+        color = field[idx].color - 1;
+
+        phase = ABS (ABS (3 - phase) - 3);
+
+        cairo_set_source_surface (cr, ball_surface,
+                                 (1.0 * j - phase) * boxsize,
+                                 (1.0 * i - color) * boxsize);
+      } else {
+        cairo_set_source_surface (cr, blank_surface, 1.0 * j * boxsize, 1.0 * i * boxsize);
+      }
+
+      cairo_fill (cr);
+    }
+  }
+
+  /* Cursor */
+  if (show_cursor) {
+    if (((backgnd.color.red + backgnd.color.green + backgnd.color.blue) / 3) > 0.5)
+      gdk_rgba_parse (&cursorColor, "#000000");
+    else
+      gdk_rgba_parse (&cursorColor, "#FFFFFF");
+
+    gdk_cairo_set_source_rgba (cr, &cursorColor);
+    cairo_set_line_width (cr, 1.0);
+    cairo_rectangle (cr,
+                     cursor_x * boxsize + 1.5, cursor_y * boxsize + 1.5,
+                     boxsize - 2.5, boxsize - 2.5);
+    cairo_stroke (cr);
+  }
+
+  draw_grid (cr);
+
+  return FALSE;
+}
+
+GtkWidget *
+game_area_init (void)
+{
+  draw_area = gtk_drawing_area_new ();
+  gtk_widget_set_size_request (draw_area, 300, 300);
+  g_signal_connect (draw_area, "button-press-event",
+                    G_CALLBACK (button_press_event), NULL);
+  g_signal_connect (draw_area, "key-press-event",
+                    G_CALLBACK (key_press_event), NULL);
+  g_signal_connect (draw_area, "configure-event",
+                    G_CALLBACK (configure_event_callback), NULL);
+  g_signal_connect (draw_area, "draw",
+                    G_CALLBACK (field_draw_callback), NULL);
+  gtk_widget_set_events (draw_area,
+                         gtk_widget_get_events (draw_area) |
+                         GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK);
+
+  gtk_widget_set_can_focus (draw_area, TRUE);
+  gtk_widget_grab_focus (draw_area);
+  return draw_area;
+}
\ No newline at end of file
diff --git a/src/game-area.h b/src/game-area.h
new file mode 100644
index 0000000..44d3303
--- /dev/null
+++ b/src/game-area.h
@@ -0,0 +1,55 @@
+/*
+ * Color lines for GNOME
+ * Copyright © 1999 Free Software Foundation
+ * Authors: Robert Szokovacs <szo appaloosacorp hu>
+ *          Szabolcs Ban <shooby gnome hu>
+ *          Karuna Grewal <karunagrewal98 gmail com>
+ * Copyright © 2007 Christian Persch
+ *
+ * This game 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, 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, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GAME_AREA_H
+#define GAME_AREA_H
+
+#include <gtk/gtk.h>
+#include "games-preimage.h"
+
+typedef struct {
+  int num;
+  int score;
+} scoretable;
+
+typedef struct {
+  int color;
+  int pathsearch;
+  int phase;
+  int active;
+  int tag;
+} field_props;
+
+GRand           **get_rgen          ();
+GamesPreimage    *get_ball_preimage ();
+gint              get_npieces       ();
+void              set_inmove        (int i);
+void              refresh_pixmaps   (void);
+void              refresh_screen    (void);
+void              load_theme        (void);
+GtkWidget       * game_area_init    (void);
+gint              get_ncolors       ();
+void              set_sizes         (gint size);
+void              reset_game        (void);
+gint              get_hfieldsize    ();
+gint              get_vfieldsize    ();
+#endif
\ No newline at end of file
diff --git a/src/meson.build b/src/meson.build
index ab170fa..de29f83 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -3,6 +3,12 @@
 five_or_more_c_sources = [
        'five-or-more.c',
        'five-or-more.h',
+       'game-area.h',
+       'game-area.c',
+       'five-or-more-app.c',
+       'five-or-more-app.h',
+       'balls-preview.c',
+       'balls-preview.h',
        'games-file-list.c',
        'games-file-list.h',
        'games-gridframe.c',


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]