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

[RFC] Add cdebconf-gtk-tetris package



Hi!

This (fairly big) patch adds a cdebconf-gtk-tetris package to the
debian-installer.  As the name suggest, this will allow you to play
Tetris within d-i.

The implementation is based on Gnometris, porting from C++ and stripping
it from most of its fancy features.

If you want to see what it looks like, you can use one of the available
mini.iso [1,2], start in expert mode and use the "Play Tetris" option in
main-menu.

[1] http://people.debian.org/~lunar/g-i+tetris-mini.iso (i386)
[2] http://people.debian.org/~lunar/g-i+tetris-mini-amd64.iso

I wonder if this patch should be integrated as is.  Maybe it would be
better to be able to start the Tetris during any progress bar.  Or while
base-installer/pkgsel are running...  Another option is just to
integrate it as the entropy plugin for the graphical frontend.

I am also unsure about the required Depends for the udeb.  Comments are
really welcome on that matter, as my original dependencies made me
report #437323.

Note: This patch depends on the integration of the fe_gtk branch, but I
won't spam the mailling-list with another huge patch to review, as there
is no significant modification from what is already in the subversion
repository.

---
 packages/cdebconf-tetris/Makefile.in               |   84 +++++
 packages/cdebconf-tetris/block_ops.c               |  297 +++++++++++++++
 packages/cdebconf-tetris/block_ops.h               |   64 ++++
 packages/cdebconf-tetris/blocks.c                  |  308 +++++++++++++++
 packages/cdebconf-tetris/blocks.h                  |   45 +++
 packages/cdebconf-tetris/configure.ac              |   16 +
 .../debian/cdebconf-gtk-tetris.install             |    1 +
 .../debian/cdebconf-gtk-tetris.postinst            |    8 +
 .../debian/cdebconf-gtk-tetris.templates           |   43 +++
 packages/cdebconf-tetris/debian/changelog          |    5 +
 packages/cdebconf-tetris/debian/compat             |    1 +
 packages/cdebconf-tetris/debian/control            |   17 +
 packages/cdebconf-tetris/debian/copyright          |   30 ++
 packages/cdebconf-tetris/debian/po/POTFILES.in     |    1 +
 packages/cdebconf-tetris/debian/rules              |   71 ++++
 packages/cdebconf-tetris/field.c                   |  286 ++++++++++++++
 packages/cdebconf-tetris/field.h                   |   52 +++
 packages/cdebconf-tetris/gtk-plugin-tetris.c       |  395 ++++++++++++++++++++
 packages/cdebconf-tetris/linker-script             |    6 +
 packages/cdebconf-tetris/preview.c                 |  166 ++++++++
 packages/cdebconf-tetris/preview.h                 |   42 ++
 packages/cdebconf-tetris/score.c                   |  182 +++++++++
 packages/cdebconf-tetris/score.h                   |   45 +++
 packages/cdebconf-tetris/tetris.h                  |   77 ++++
 24 files changed, 2242 insertions(+), 0 deletions(-)
 create mode 100644 packages/cdebconf-tetris/Makefile.in
 create mode 100644 packages/cdebconf-tetris/block_ops.c
 create mode 100644 packages/cdebconf-tetris/block_ops.h
 create mode 100644 packages/cdebconf-tetris/blocks.c
 create mode 100644 packages/cdebconf-tetris/blocks.h
 create mode 100644 packages/cdebconf-tetris/configure.ac
 create mode 100644 packages/cdebconf-tetris/debian/cdebconf-gtk-tetris.install
 create mode 100644 packages/cdebconf-tetris/debian/cdebconf-gtk-tetris.postinst
 create mode 100644 packages/cdebconf-tetris/debian/cdebconf-gtk-tetris.templates
 create mode 100644 packages/cdebconf-tetris/debian/changelog
 create mode 100644 packages/cdebconf-tetris/debian/compat
 create mode 100644 packages/cdebconf-tetris/debian/control
 create mode 100644 packages/cdebconf-tetris/debian/copyright
 create mode 100644 packages/cdebconf-tetris/debian/po/POTFILES.in
 create mode 100755 packages/cdebconf-tetris/debian/rules
 create mode 100644 packages/cdebconf-tetris/field.c
 create mode 100644 packages/cdebconf-tetris/field.h
 create mode 100644 packages/cdebconf-tetris/gtk-plugin-tetris.c
 create mode 100644 packages/cdebconf-tetris/linker-script
 create mode 100644 packages/cdebconf-tetris/preview.c
 create mode 100644 packages/cdebconf-tetris/preview.h
 create mode 100644 packages/cdebconf-tetris/score.c
 create mode 100644 packages/cdebconf-tetris/score.h
 create mode 100644 packages/cdebconf-tetris/tetris.h

diff --git a/packages/cdebconf-tetris/Makefile.in b/packages/cdebconf-tetris/Makefile.in
new file mode 100644
index 0000000..e60f2d9
--- /dev/null
+++ b/packages/cdebconf-tetris/Makefile.in
@@ -0,0 +1,84 @@
+prefix = @prefix@
+etcdir = @sysconfdir@
+bindir = ${prefix}/bin
+sbindir = ${prefix}/sbin
+libdir = ${prefix}/lib
+moddir = ${libdir}/cdebconf/frontend
+sharedir = ${prefix}/share/debconf
+mandir = ${prefix}/share/man
+incdir = ${prefix}/include/cdebconf
+
+CC = @CC@
+CFLAGS = @CFLAGS@ @GTK_CFLAGS@ -I.
+LDFLAGS = @LDFLAGS@ @LIBS@ @GTK_LIBS@
+
+# Export only strictly needed symbols
+LDFLAGS += "-Wl,--version-script=linker-script"
+
+# let the type char be unsigned by default
+CFLAGS += -funsigned-char
+# apply strict aliasing rules
+CFLAGS += -fstrict-aliasing
+# turn on all common warnings
+CFLAGS += -Wall
+# turn on extra warnings
+CFLAGS += -W
+# treat warnings as errors
+CFLAGS += -Werror
+# warn about undefined preprocessor identifiers
+CFLAGS += -Wundef
+# warn about casting of pointers to increased alignment requirements
+CFLAGS += -Wcast-align
+# make string constants const
+CFLAGS += -Wwrite-strings
+# warn about comparisons between signed and unsigned values
+CFLAGS += -Wsign-compare
+# warn about unused declared stuff
+CFLAGS += -Wno-unused-parameter
+# warn about variables which are initialized with themselves
+CFLAGS += -Winit-self
+# warn about pointer arithmetic on void* and function pointers
+CFLAGS += -Wpointer-arith
+# warn about multiple declarations
+CFLAGS += -Wredundant-decls
+# do not warn about zero-length formats.
+CFLAGS += -Wno-format-zero-length
+# missing prototypes
+CFLAGS += -Wmissing-prototypes
+# warn about functions without format attribute that should have one
+CFLAGS += -Wmissing-format-attribute
+
+PLUGIN_MODULES = gtk-plugin-tetris.so
+
+SOURCES = \
+	gtk-plugin-tetris.c tetris.h \
+	blocks.c blocks.h \
+	block_ops.c block_ops.h \
+	field.c field.h \
+	preview.c preview.h \
+	score.c score.h
+
+OBJS = $(filter %.opic,$(subst .c,.opic,$(SOURCES)))
+
+all: $(PLUGIN_MODULES)
+
+install: $(PLUGIN_MODULES)
+	for p in $(PLUGIN_MODULES); do \
+		install -m755 -d $(DESTDIR)/$(moddir)/$${p%%-*} ; \
+		install -m644 $$p $(DESTDIR)/$(moddir)/$${p%%-*}/$${p#*-} ; \
+	done
+
+clean:
+	rm -f $(PLUGIN_MODULES)
+	rm -f $(OBJS)
+
+distclean: clean
+	rm -f config.log config.status
+	rm -f Makefile
+
+gtk-plugin-tetris.so: $(OBJS)
+	$(CC) $(LDFLAGS) -shared -o $@ $(OBJS)
+
+%.opic: %.c
+	$(CC) $(CFLAGS) -fPIC -o $@ -c $<
+
diff --git a/packages/cdebconf-tetris/block_ops.c b/packages/cdebconf-tetris/block_ops.c
new file mode 100644
index 0000000..c7d0a9b
--- /dev/null
+++ b/packages/cdebconf-tetris/block_ops.c
@@ -0,0 +1,297 @@
+/*
+ * Copyright © 2007 Jérémy Bobbio <lunar@debian.org>
+ *
+ * Based on Gnometris, written by J. Marcin Gorycki <marcin.gorycki@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "block_ops.h"
+
+#include <glib.h>
+
+#include "tetris.h"
+#include "blocks.h"
+
+gboolean block_ok_here(struct tetris * tetris, int dx, int dy, int mr)
+{
+    int x = tetris->posx + dx;
+    int y = tetris->posy + dy;
+    int b = tetris->blocknr;
+    int r = -1 == mr ? tetris->rot : mr;
+    int x1;
+    int y1;
+
+    x -= 2;
+
+    for (x1 = 0; x1 < 4; ++x1) {
+        for (y1 = 0; y1 < 4; ++y1) {
+            if (BLOCK_TABLE[b][r][x1][y1] && (x1 + x < 0)) {
+                return FALSE;
+            }
+            if (BLOCK_TABLE[b][r][x1][y1] && (x1 + x >= COLUMNS)) {
+                return FALSE;
+            }
+            if (BLOCK_TABLE[b][r][x1][y1] && (y1 + y >= LINES)) {
+                return FALSE;
+            }
+            if (BLOCK_TABLE[b][r][x1][y1] &&
+                LAYING == tetris->blocks[x + x1][y1 + y].what) {
+                return FALSE;
+            }
+        }
+    }
+
+    return TRUE;
+}
+
+int get_lines_to_bottom(struct tetris * tetris)
+{
+    int lines = LINES;
+    int x;
+    int y;
+    int yy;
+    int tmp;
+
+    for (x = 0; x < 4; ++x) {
+        for (y = 3; y >= 0; --y) {
+            if (!BLOCK_TABLE[tetris->blocknr][tetris->rot][x][y]) {
+                continue;
+            }
+            for (yy = tetris->posy + y; yy < LINES; ++yy) {
+                if (LAYING == tetris->blocks[tetris->posx + x - 2][yy].what) {
+                    break;
+                }
+            }
+            tmp = yy - tetris->posy - y;
+            if (lines > tmp) {
+                lines = tmp;
+            }
+        }
+    }
+
+    return lines;
+}
+
+gboolean move_block_left(struct tetris * tetris)
+{
+    if (!block_ok_here(tetris, -1, 0, -1)) {
+        return FALSE;
+    }
+    put_block_in_field(tetris, EMPTY);
+    --tetris->posx;
+    put_block_in_field(tetris, FALLING);
+    return TRUE;
+}
+
+gboolean move_block_right(struct tetris * tetris)
+{
+    if (!block_ok_here(tetris, 1, 0, -1)) {
+        return FALSE;
+    }
+    put_block_in_field(tetris, EMPTY);
+    ++tetris->posx;
+    put_block_in_field(tetris, FALLING);
+    return TRUE;
+}
+
+#define ROTATE_COUNTER_CLOCK_WISE TRUE
+#define ROTATE_CLOCK_WISE FALSE
+
+gboolean rotate_block(struct tetris * tetris, gboolean rotate_ccw)
+{
+    int r = tetris->rot;
+
+    if (rotate_ccw) {
+        if (--r < 0) {
+            r = 3;
+        }
+    } else {
+        if (++r >= 4) {
+            r = 0;
+        }
+    }
+
+    if (!block_ok_here(tetris, 0, 0, r)) {
+        return FALSE;
+    }
+    put_block_in_field(tetris, EMPTY);
+    tetris->rot = r;
+    put_block_in_field(tetris, FALLING);
+    return TRUE;
+}
+
+gboolean move_block_down(struct tetris * tetris)
+{
+    if (!block_ok_here(tetris, 0, 1, -1)) {
+        return TRUE;
+    }
+    put_block_in_field(tetris, EMPTY);
+    ++tetris->posy;
+    put_block_in_field(tetris, FALLING);
+    return FALSE;
+}
+
+int drop_block(struct tetris * tetris)
+{
+    int count = 0;
+
+    while (!move_block_down(tetris)) {
+        count++;
+    }
+
+    return count;
+}
+
+void falling_to_laying(struct tetris * tetris)
+{
+    int x;
+    int y;
+
+    for (x = 0; x < COLUMNS; ++x) {
+        for (y = 0; y < LINES; ++y) {
+            if (FALLING == tetris->blocks[x][y].what) {
+                tetris->blocks[x][y].what = LAYING;
+            }
+        }
+    }
+}
+
+void eliminate_line(struct tetris * tetris, int l)
+{
+    int y;
+    int x;
+
+    for (y = l; y > 0; --y) {
+        for (x = 0; x < COLUMNS; ++x) {
+            tetris->blocks[x][y] = tetris->blocks[x][y - 1];
+
+            tetris->blocks[x][y - 1].what = EMPTY;
+            tetris->blocks[x][y - 1].color = 0;
+        }
+    }
+}
+
+int check_full_lines(struct tetris * tetris)
+{
+    /* we can have at most 4 full lines (vertical block) */
+    int full_lines[4] = {0, 0, 0, 0};
+    int num_full_lines = 0;
+    int x;
+    int y;
+    int i;
+    gboolean f;
+
+    for (y = tetris->posy; y < MIN(tetris->posy + 4, LINES); ++y) {
+        f = TRUE;
+        for (x = 0; x < COLUMNS; ++x) {
+            if (tetris->blocks[x][y].what != LAYING) {
+                f = FALSE;
+                break;
+            }
+        }
+
+        if (f) {
+            full_lines[num_full_lines] = y;
+            ++num_full_lines;
+        }
+    }
+
+    if (num_full_lines > 0) {
+        for (i = 0; i < num_full_lines; ++i) {
+            eliminate_line(tetris, full_lines[i]);
+        }
+    }
+
+    return num_full_lines;
+}
+
+gboolean generate_falling_block(struct tetris * tetris)
+{
+    tetris->posx = COLUMNS / 2 + 1;
+    tetris->posy = 0;
+
+    tetris->blocknr = tetris->blocknr_next == -1 ?
+        g_random_int_range(0, BLOCK_TYPES) :
+        tetris->blocknr_next;
+    tetris->rot = tetris->rot_next == -1 ?
+        g_random_int_range(0, 4) :
+        tetris->rot_next;
+
+    tetris->blocknr_next = g_random_int_range(0, BLOCK_TYPES);
+    tetris->rot_next = g_random_int_range(0, 4);
+
+    if (!block_ok_here(tetris, 0, 0, -1)) {
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+void empty_field(struct tetris * tetris)
+{
+    int y;
+    int x;
+
+    for (y = 0; y < LINES; ++y) {
+        for (x = 0; x < COLUMNS; ++x) {
+            tetris->blocks[x][y].what = EMPTY;
+            tetris->blocks[x][y].color = 0; 
+        }
+    }
+}
+
+void put_block_in_field(struct tetris * tetris, SlotType fill)
+{
+    int bx = tetris->posx;
+    int by = tetris->posy;
+    int x;
+    int y;
+    int i;
+    int j;
+
+    for (x = 0; x < 4; ++x) {
+        for (y = 0; y < 4; ++y) {
+            if (BLOCK_TABLE[tetris->blocknr][tetris->rot][x][y]) {
+                i = bx - 2 + x;
+                j = y + by;
+
+                tetris->blocks[i][j].what = fill;
+                if ((FALLING == fill) || (LAYING == fill)) {
+                    tetris->blocks[i][j].color = tetris->blocknr % BLOCK_TYPES;
+                } else {
+                    tetris->blocks[i][j].color = 0;
+                }
+            }
+        }
+    }
+}
+
+gboolean is_field_empty(struct tetris * tetris)
+{
+    int x;
+
+    for (x = 0; x < COLUMNS; x++) {
+        if (EMPTY != tetris->blocks[x][LINES - 1].what) {
+            return FALSE;
+        }
+    }
+
+    return TRUE;
+}
+
+/* vim: et sw=4 si
+ */
diff --git a/packages/cdebconf-tetris/block_ops.h b/packages/cdebconf-tetris/block_ops.h
new file mode 100644
index 0000000..2c219f9
--- /dev/null
+++ b/packages/cdebconf-tetris/block_ops.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright © 2007 Jérémy Bobbio <lunar@debian.org>
+ *
+ * Based on Gnometris, written by J. Marcin Gorycki <marcin.gorycki@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _BLOCK_OPS_H_
+#define _BLOCK_OPS_H_
+
+#include <glib.h>
+
+#include "tetris.h"
+#include "blocks.h"
+
+gboolean block_ok_here(struct tetris * tetris, int dx, int dy, int mr);
+
+int get_lines_to_bottom(struct tetris * tetris);
+
+gboolean move_block_left(struct tetris * tetris);
+
+gboolean move_block_right(struct tetris * tetris);
+
+#define ROTATE_COUNTER_CLOCK_WISE TRUE
+#define ROTATE_CLOCK_WISE FALSE
+
+gboolean rotate_block(struct tetris * tetris, gboolean rotate_ccw);
+
+gboolean move_block_down(struct tetris * tetris);
+
+int drop_block(struct tetris * tetris);
+
+void falling_to_laying(struct tetris * tetris);
+
+void eliminate_line(struct tetris * tetris, int l);
+
+int check_full_lines(struct tetris * tetris);
+
+gboolean generate_falling_block(struct tetris * tetris);
+
+void empty_field(struct tetris * tetris);
+
+void put_block_in_field(struct tetris * tetris, SlotType fill);
+
+gboolean is_field_empty(struct tetris * tetris);
+
+#endif /* !_BLOCK_OPS_H_ */
+
+/* vim: et sw=4 si
+ */
diff --git a/packages/cdebconf-tetris/blocks.c b/packages/cdebconf-tetris/blocks.c
new file mode 100644
index 0000000..570b5af
--- /dev/null
+++ b/packages/cdebconf-tetris/blocks.c
@@ -0,0 +1,308 @@
+/*
+ * Copyright © 2007 Jérémy Bobbio <lunar@debian.org>
+ *
+ * Based on Gnometris, written by J. Marcin Gorycki <marcin.gorycki@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "blocks.h"
+
+const int BLOCK_TABLE[BLOCK_TYPES][4][4][4] = {
+    {
+        {
+            {0, 0, 0, 0},
+            {1, 1, 1, 0},
+            {1, 0, 0, 0},
+            {0, 0, 0, 0},
+        },
+        {
+            {0, 1, 0, 0},
+            {0, 1, 0, 0},
+            {0, 1, 1, 0},
+            {0, 0, 0, 0},
+        },
+        {
+            {0, 0, 1, 0},
+            {1, 1, 1, 0},
+            {0, 0, 0, 0},
+            {0, 0, 0, 0},
+        },
+        {
+            {1, 1, 0, 0},
+            {0, 1, 0, 0},
+            {0, 1, 0, 0},
+            {0, 0, 0, 0},
+        },
+
+    },
+
+    {
+        {
+            {0, 0, 0, 0},
+            {1, 1, 1, 0},
+            {0, 0, 1, 0},
+            {0, 0, 0, 0},
+        },
+        {
+            {0, 1, 1, 0},
+            {0, 1, 0, 0},
+            {0, 1, 0, 0},
+            {0, 0, 0, 0},
+        },
+        {
+            {1, 0, 0, 0},
+            {1, 1, 1, 0},
+            {0, 0, 0, 0},
+            {0, 0, 0, 0},
+        },
+        {
+            {0, 1, 0, 0},
+            {0, 1, 0, 0},
+            {1, 1, 0, 0},
+            {0, 0, 0, 0},
+        },
+    },
+
+    {
+        {
+            {0, 0, 0, 0},
+            {1, 1, 1, 0},
+            {0, 1, 0, 0},
+            {0, 0, 0, 0},
+        },
+        {
+            {0, 1, 0, 0},
+            {0, 1, 1, 0},
+            {0, 1, 0, 0},
+            {0, 0, 0, 0},
+        },
+        {
+            {0, 1, 0, 0},
+            {1, 1, 1, 0},
+            {0, 0, 0, 0},
+            {0, 0, 0, 0},
+        },
+        {
+            {0, 1, 0, 0},
+            {1, 1, 0, 0},
+            {0, 1, 0, 0},
+            {0, 0, 0, 0},
+        },
+    },
+
+    {
+        {
+            {0, 0, 0, 0},
+            {0, 1, 1, 0},
+            {1, 1, 0, 0},
+            {0, 0, 0, 0},
+        },
+        {
+            {0, 1, 0, 0},
+            {0, 1, 1, 0},
+            {0, 0, 1, 0},
+            {0, 0, 0, 0},
+        },
+        {
+            {0, 1, 1, 0},
+            {1, 1, 0, 0},
+            {0, 0, 0, 0},
+            {0, 0, 0, 0},
+        },
+        {
+            {1, 0, 0, 0},
+            {1, 1, 0, 0},
+            {0, 1, 0, 0},
+            {0, 0, 0, 0},
+        },
+    },
+
+    {
+        {
+            {0, 0, 0, 0},
+            {1, 1, 0, 0},
+            {0, 1, 1, 0},
+            {0, 0, 0, 0},
+        },
+        {
+            {0, 0, 1, 0},
+            {0, 1, 1, 0},
+            {0, 1, 0, 0},
+            {0, 0, 0, 0},
+        },
+        {
+            {1, 1, 0, 0},
+            {0, 1, 1, 0},
+            {0, 0, 0, 0},
+            {0, 0, 0, 0},
+        },
+        {
+            {0, 1, 0, 0},
+            {1, 1, 0, 0},
+            {1, 0, 0, 0},
+            {0, 0, 0, 0},
+        },
+    },
+
+    {
+        {
+            {0, 0, 0, 0},
+            {1, 1, 1, 1},
+            {0, 0, 0, 0},
+            {0, 0, 0, 0},
+        },
+        {
+            {0, 1, 0, 0},
+            {0, 1, 0, 0},
+            {0, 1, 0, 0},
+            {0, 1, 0, 0},
+        },
+        {
+            {0, 0, 0, 0},
+            {1, 1, 1, 1},
+            {0, 0, 0, 0},
+            {0, 0, 0, 0},
+        },
+        {
+            {0, 1, 0, 0},
+            {0, 1, 0, 0},
+            {0, 1, 0, 0},
+            {0, 1, 0, 0},
+        },
+    },
+
+    {
+        {
+            {0, 0, 0, 0},
+            {0, 1, 1, 0},
+            {0, 1, 1, 0},
+            {0, 0, 0, 0},
+        },
+        {
+            {0, 0, 0, 0},
+            {0, 1, 1, 0},
+            {0, 1, 1, 0},
+            {0, 0, 0, 0},
+        },
+        {
+            {0, 0, 0, 0},
+            {0, 1, 1, 0},
+            {0, 1, 1, 0},
+            {0, 0, 0, 0},
+        },
+        {
+            {0, 0, 0, 0},
+            {0, 1, 1, 0},
+            {0, 1, 1, 0},
+            {0, 0, 0, 0},
+        },
+    }
+};
+
+const int SIZE_TABLE[BLOCK_TYPES][4][2] = {
+    {
+        {3, 2},
+        {2, 3},
+        {3, 2},
+        {2, 3},
+    },
+    {
+        {3, 2},
+        {2, 3},
+        {3, 2},
+        {2, 3},
+    },
+    {
+        {3, 2},
+        {2, 3},
+        {3, 2},
+        {2, 3},
+    },
+    {
+        {3, 2},
+        {2, 3},
+        {3, 2},
+        {2, 3},
+    },
+    {
+        {3, 2},
+        {2, 3},
+        {3, 2},
+        {2, 3},
+    },
+    {
+        {4, 1},
+        {1, 4},
+        {4, 1},
+        {1, 4},
+    },
+    {
+        {2, 2},
+        {2, 2},
+        {2, 2},
+        {2, 2},
+    },
+};
+		
+const int OFFSET_TABLE[BLOCK_TYPES][4][2] = {
+    {
+        {0, 1},
+        {1, 0},
+        {0, 0},
+        {0, 0},
+
+    },
+    {
+        {0, 1},
+        {1, 0},
+        {0, 0},
+        {0, 0},
+    },
+    {
+        {0, 1},
+        {1, 0},
+        {0, 0},
+        {0, 0},
+    },
+    {
+        {0, 1},
+        {1, 0},
+        {0, 0},
+        {0, 0},
+    },
+    {
+        {0, 1},
+        {1, 0},
+        {0, 0},
+        {0, 0},
+    },
+    {
+        {0, 1},
+        {1, 0},
+        {0, 2},
+        {2, 0},
+    },
+    {
+        {1, 1},
+        {1, 1},
+        {1, 1},
+        {1, 1},
+    },
+};
+
+/* vim: et sw=4 si
+ */
diff --git a/packages/cdebconf-tetris/blocks.h b/packages/cdebconf-tetris/blocks.h
new file mode 100644
index 0000000..9066492
--- /dev/null
+++ b/packages/cdebconf-tetris/blocks.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright © 2007 Jérémy Bobbio <lunar@debian.org>
+ *
+ * Based on Gnometris, written by J. Marcin Gorycki <marcin.gorycki@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _BLOCKS_H_
+#define _BLOCKS_H_
+
+typedef enum {
+    EMPTY = 0,
+    FALLING,
+    LAYING
+} SlotType;
+
+struct block {
+    SlotType what;
+    int color;
+};
+
+#define BLOCK_TYPES 7
+
+extern const int BLOCK_TABLE[BLOCK_TYPES][4][4][4];
+extern const int SIZE_TABLE[BLOCK_TYPES][4][2];
+extern const int OFFSET_TABLE[BLOCK_TYPES][4][2];
+
+#endif /* !_BLOCKS_H_ */
+
+/* vim: et sw=4 si
+ */
diff --git a/packages/cdebconf-tetris/configure.ac b/packages/cdebconf-tetris/configure.ac
new file mode 100644
index 0000000..d381c51
--- /dev/null
+++ b/packages/cdebconf-tetris/configure.ac
@@ -0,0 +1,16 @@
+AC_INIT
+PACKAGE=tetris
+AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE")
+
+AC_PROG_MAKE_SET
+AC_PROG_CC
+
+dnl PKG_CHECK_MODULES(GTK, [gtk+-2.0])
+PKG_CHECK_MODULES(GTK, [gtk+-directfb-2.0])
+
+AC_CHECK_LIB(m, pow)
+
+AC_SUBST(GTK_CFLAGS)
+AC_SUBST(GTK_LIBS)
+
+AC_OUTPUT(Makefile)
diff --git a/packages/cdebconf-tetris/debian/cdebconf-gtk-tetris.install b/packages/cdebconf-tetris/debian/cdebconf-gtk-tetris.install
new file mode 100644
index 0000000..3a7472e
--- /dev/null
+++ b/packages/cdebconf-tetris/debian/cdebconf-gtk-tetris.install
@@ -0,0 +1 @@
+usr/lib/cdebconf/frontend/gtk
diff --git a/packages/cdebconf-tetris/debian/cdebconf-gtk-tetris.postinst b/packages/cdebconf-tetris/debian/cdebconf-gtk-tetris.postinst
new file mode 100644
index 0000000..8125948
--- /dev/null
+++ b/packages/cdebconf-tetris/debian/cdebconf-gtk-tetris.postinst
@@ -0,0 +1,8 @@
+#! /bin/sh -e
+. /usr/share/debconf/confmodule
+
+db_capb
+
+db_fset cdebconf-gtk-tetris/tetris seen false
+db_input critical cdebconf-gtk-tetris/tetris || true
+db_go || true
diff --git a/packages/cdebconf-tetris/debian/cdebconf-gtk-tetris.templates b/packages/cdebconf-tetris/debian/cdebconf-gtk-tetris.templates
new file mode 100644
index 0000000..29d9805
--- /dev/null
+++ b/packages/cdebconf-tetris/debian/cdebconf-gtk-tetris.templates
@@ -0,0 +1,43 @@
+Template: cdebconf-gtk-tetris/tetris
+Type: tetris
+_Description: Play Tetris
+
+# The following keys are available:
+#  Left/arrows: Move block left/right - Up arrow: Rotate block
+#  Down arrow: Fast fall - Spacebar: Drop block - P: Pause
+
+Template: cdebconf-gtk-tetris/paused
+Type: text
+# Translators: this will appear in the play field
+_Description: Paused
+
+Template: cdebconf-gtk-tetris/game-over
+Type: text
+# Translators: this will appear on the play field
+_Description: Game Over
+
+Template: cdebconf-gtk-tetris/new-game
+Type: text
+# Translators: this will appear on a button
+_Description: New game
+
+Template: cdebconf-gtk-tetris/end-game
+Type: text
+# Translators: this will appear on a button
+_Description: End game
+
+Template: cdebconf-gtk-tetris/pause
+Type: text
+# Translators: this will appear on a button
+_Description: Pause
+
+Template: cdebconf-gtk-tetris/resume
+Type: text
+# Translators: this will appear on a button
+_Description: Resume
+
+Template: debian-installer/cdebconf-gtk-tetris/title
+Type: text
+#  Main menu item
+# Translators: keep it under 65 columns
+_Description: Play Tetris
diff --git a/packages/cdebconf-tetris/debian/changelog b/packages/cdebconf-tetris/debian/changelog
new file mode 100644
index 0000000..939f18b
--- /dev/null
+++ b/packages/cdebconf-tetris/debian/changelog
@@ -0,0 +1,5 @@
+cdebconf-tetris (1) UNRELEASED; urgency=low
+
+  * Initial release. (Closes: #XXXXXX)
+
+ -- Jérémy Bobbio <lunar@debian.org>  Thu, 09 Aug 2007 12:13:32 +0200
diff --git a/packages/cdebconf-tetris/debian/compat b/packages/cdebconf-tetris/debian/compat
new file mode 100644
index 0000000..7ed6ff8
--- /dev/null
+++ b/packages/cdebconf-tetris/debian/compat
@@ -0,0 +1 @@
+5
diff --git a/packages/cdebconf-tetris/debian/control b/packages/cdebconf-tetris/debian/control
new file mode 100644
index 0000000..ec1178d
--- /dev/null
+++ b/packages/cdebconf-tetris/debian/control
@@ -0,0 +1,17 @@
+Source: cdebconf-tetris
+Priority: extra
+Section: debian-installer
+Maintainer: Debian Install System Team <debian-boot@lists.debian.org>
+Uploaders: Jérémy Bobbio <lunar@debian.org>
+Build-Depends: debhelper (>= 5), libgtk-directfb-2.0-dev,
+ libdebconfclient0-dev (>> 0.119)
+Standards-Version: 3.7.2
+XS-Vcs-Svn: svn://svn.debian.org/d-i/trunk/packages/cdebconf-tetris
+
+Package: cdebconf-gtk-tetris
+Architecture: any
+Section: debian-installer
+XC-Package-Type: udeb
+XB-Installer-Menu-Item: 95000
+Description: Play Tetris
+ This udeb will add a Tetris to the graphical version of the debian-installer.
diff --git a/packages/cdebconf-tetris/debian/copyright b/packages/cdebconf-tetris/debian/copyright
new file mode 100644
index 0000000..d402e02
--- /dev/null
+++ b/packages/cdebconf-tetris/debian/copyright
@@ -0,0 +1,30 @@
+Tetris plugin for the GTK+ frontend of cdebconf
+
+Author:
+
+  Jérémy Bobbio <lunar@debian.org>
+
+Copyright:
+
+  © 2007 Jérémy Bobbio <lunar@debian.org>
+
+This work is based on Gnometris, written by:
+
+  J. Marcin Gorycki <marcin.gorycki@intel.com>
+
+License:
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License with
+  the Debian GNU/Linux distribution in file /usr/share/common-licenses/GPL;
+  if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth
+  Floor, Boston, MA  02110-1301  USA
diff --git a/packages/cdebconf-tetris/debian/po/POTFILES.in b/packages/cdebconf-tetris/debian/po/POTFILES.in
new file mode 100644
index 0000000..f8ab290
--- /dev/null
+++ b/packages/cdebconf-tetris/debian/po/POTFILES.in
@@ -0,0 +1 @@
+[type: gettext/rfc822deb] cdebconf-gtk-tetris.templates
diff --git a/packages/cdebconf-tetris/debian/rules b/packages/cdebconf-tetris/debian/rules
new file mode 100755
index 0000000..9479f58
--- /dev/null
+++ b/packages/cdebconf-tetris/debian/rules
@@ -0,0 +1,71 @@
+#! /usr/bin/make -f
+
+#export DH_VERBOSE=1
+
+DEB_HOST_GNU_TYPE   ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
+DEB_BUILD_GNU_TYPE  ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
+
+CFLAGS = -Wall -g
+
+ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
+	CFLAGS += -O0
+else
+	CFLAGS += -O2
+endif
+
+ifeq ($(DEB_BUILD_GNU_TYPE), $(DEB_HOST_GNU_TYPE))
+	confflags += --build $(DEB_HOST_GNU_TYPE)
+else
+	confflags += --build $(DEB_BUILD_GNU_TYPE) --host $(DEB_HOST_GNU_TYPE)
+endif   
+
+config.status: configure
+	dh_testdir
+	CFLAGS="$(CFLAGS)" LDFLAGS="-Wl,-z,syms" \
+		./configure $(confflags) --prefix=/usr
+
+build: build-stamp
+build-stamp: config.status
+	dh_testdir
+	$(MAKE)
+	touch build-stamp
+
+clean:
+	dh_testdir
+	dh_testroot
+	rm -f build-stamp 
+	-$(MAKE) distclean
+ifneq "$(wildcard /usr/share/misc/config.sub)" ""
+	cp -f /usr/share/misc/config.sub config.sub
+endif
+ifneq "$(wildcard /usr/share/misc/config.guess)" ""
+	cp -f /usr/share/misc/config.guess config.guess
+endif
+	dh_clean
+
+install: build
+	dh_testdir
+	dh_testroot
+	dh_clean -k 
+	dh_installdirs
+	$(MAKE) install DESTDIR=$(CURDIR)/debian/tmp
+
+binary-indep: build install
+	# We have nothing to do.
+
+binary-arch: build install
+	dh_testdir
+	dh_testroot
+	dh_install --sourcedir=debian/tmp
+	dh_installdebconf
+	dh_strip
+	dh_fixperms
+	dh_installdeb
+	dh_shlibdeps
+	dh_gencontrol
+	dh_md5sums
+	dh_builddeb
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install 
+
diff --git a/packages/cdebconf-tetris/field.c b/packages/cdebconf-tetris/field.c
new file mode 100644
index 0000000..7cd39a4
--- /dev/null
+++ b/packages/cdebconf-tetris/field.c
@@ -0,0 +1,286 @@
+/*
+ * Copyright © 2007 Jérémy Bobbio <lunar@debian.org>
+ *
+ * Based on Gnometris, written by J. Marcin Gorycki <marcin.gorycki@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "field.h"
+
+#include <gtk/gtk.h>
+#include <cairo/cairo.h>
+
+#include <cdebconf/cdebconf_gtk.h>
+
+#include "tetris.h"
+#include "blocks.h"
+
+#define FONT "Sans Bold"
+
+struct field {
+    struct tetris * tetris;
+    GtkWidget * drawing_area;
+    int pixel_width;
+    int pixel_height;
+    cairo_surface_t * buffer;
+    MessageType show_message;
+    struct block ** blocks;
+};
+
+void draw_cell(cairo_t * cr, struct block * block, int x, int y)
+{
+    const gdouble colours[7][3] = {
+        {1.0, 0.0, 0.0},
+        {0.0, 1.0, 0.0},
+        {0.0, 0.0, 1.0},
+        {1.0, 1.0, 1.0},
+        {1.0, 1.0, 0.0},
+        {1.0, 0.0, 1.0},
+        {0.0, 1.0, 1.0}
+    };
+    int i;
+
+    if (EMPTY == block->what) {
+        return;
+    }
+
+    i = block->color;                       
+    i = CLAMP(i, 0, 6);
+
+    cairo_set_source_rgb(cr, colours[i][0], colours[i][1], colours[i][2]);
+
+    cairo_rectangle(cr, x + 0.05, y + 0.05, 0.9, 0.9);
+    cairo_fill(cr);
+}
+
+void draw_background(cairo_t * cr)
+{
+    cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
+    cairo_paint(cr);
+}
+
+static void draw_buffer(struct field * field)
+{
+    cairo_t * cr;
+    int x;
+    int y;
+
+    cr = cairo_create(field->buffer);
+
+    draw_background(cr);
+
+    cairo_scale(cr, 1.0 * field->pixel_width / COLUMNS, 1.0 * field->pixel_height / LINES);
+
+    for (y = 0; y < LINES; y++) {
+        for (x = 0; x < COLUMNS; x++) {
+            draw_cell(cr, &field->tetris->blocks[x][y], x, y);
+        }
+    }
+
+    cairo_destroy(cr);
+}
+
+static void draw_widget(struct field * field, gint x, gint y, gint wd, gint ht)
+{
+    cairo_t * cr;
+
+    cr = gdk_cairo_create(field->drawing_area->window);
+
+    cairo_set_source_surface(cr, field->buffer, 0, 0);
+    cairo_rectangle(cr, x, y, wd, ht);
+    cairo_fill(cr);
+
+    cairo_destroy(cr);
+}
+
+static void draw_message(struct field * field, cairo_t * cr, const char * msg)
+{
+    PangoLayout * dummy_layout;
+    PangoLayout * layout;
+    PangoFontDescription * desc;
+    int lw;
+    int lh;
+
+    cairo_save(cr);
+
+    // Center coordinates
+    cairo_translate(cr, field->pixel_width / 2, field->pixel_height / 2);
+
+    desc = pango_font_description_from_string(FONT);
+
+    layout = pango_cairo_create_layout(cr);
+    pango_layout_set_text(layout, msg, -1);
+
+    dummy_layout = pango_layout_copy(layout);
+    pango_layout_set_font_description(dummy_layout, desc);
+    pango_layout_get_size(dummy_layout, &lw, &lh);
+    g_object_unref(dummy_layout);
+
+    /* desired height : lh = widget width * 0.9 : lw */
+    pango_font_description_set_absolute_size(
+        desc, ((float) lh / lw) * PANGO_SCALE * field->pixel_width * 0.8);
+    pango_layout_set_font_description(layout, desc);
+    pango_font_description_free(desc);
+
+    pango_layout_get_size(layout, &lw, &lh);
+    cairo_move_to(cr, -((double)lw / PANGO_SCALE) / 2,
+                  -((double)lh / PANGO_SCALE) / 2);
+    pango_cairo_layout_path(cr, layout);
+    cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
+    cairo_fill_preserve(cr);
+    cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
+    /* A linewidth of 2 pixels at the default size. */
+    cairo_set_line_width(cr, field->pixel_width / 220.0);
+    cairo_stroke(cr);
+
+    g_object_unref(layout);
+
+    cairo_restore(cr);
+}
+
+static gboolean expose(GtkWidget * widget, GdkEventExpose * event,
+                       struct field * field)
+{
+    draw_widget(field, event->area.x, event->area.y, event->area.width,
+                event->area.height);
+
+    return TRUE;
+}
+
+static gboolean configure(GtkWidget * widget, GdkEventConfigure * event,
+                          struct field * field)
+{
+    cairo_t * cr;
+
+    field->pixel_width = widget->allocation.width;
+    field->pixel_height = widget->allocation.height;
+
+    cr = gdk_cairo_create(widget->window);
+
+    if (field->buffer) {
+        cairo_surface_destroy(field->buffer);
+    }
+    field->buffer = cairo_surface_create_similar(
+        cairo_get_target(cr), CAIRO_CONTENT_COLOR, widget->allocation.width,
+        widget->allocation.height);
+
+    cairo_destroy(cr);
+
+    return TRUE;
+}
+
+struct field * create_field(struct tetris * tetris, GtkWidget * container)
+{
+    struct field * field;
+    GtkWidget * aspect_frame;
+    GtkWidget * drawing_area;
+
+    if (NULL == (field = g_malloc0(sizeof (struct field)))) {
+        g_warning("g_malloc0 failed.");
+        return NULL;
+    }
+
+    field->tetris = tetris;
+    field->pixel_width = -1;
+    field->pixel_height = -1;
+    field->buffer = NULL;
+    field->show_message = MESSAGE_NONE;
+
+    aspect_frame = gtk_aspect_frame_new(
+        NULL /* no label */, 0.5 /* center */, 0.5 /* middle */,
+        (float) COLUMNS / (float) LINES, FALSE /* enforce ratio */);
+    if (NULL == aspect_frame) {
+        g_warning("gtk_aspect_frame_new failed.");
+        g_free(field);
+        return NULL;
+    }
+    gtk_frame_set_shadow_type(GTK_FRAME (aspect_frame), GTK_SHADOW_NONE);
+
+    if (NULL == (drawing_area = gtk_drawing_area_new())) {
+        g_warning("gtk_drawing_area_new failed.");
+        g_free(field);
+        return NULL;
+    }
+
+    g_signal_connect(drawing_area, "expose_event",
+                     G_CALLBACK(expose), field);
+    g_signal_connect(drawing_area, "configure_event",
+                     G_CALLBACK(configure), field);
+
+    gtk_widget_set_size_request(drawing_area, COLUMNS * 190 / LINES, 190);
+
+    g_object_ref(drawing_area);
+    field->drawing_area = drawing_area;
+
+    gtk_container_add(GTK_CONTAINER(aspect_frame), drawing_area);
+    gtk_box_pack_start_defaults(GTK_BOX(container), aspect_frame);
+
+    return field;
+}
+
+void destroy_field(struct field * field)
+{
+    if (NULL == field) {
+        return;
+    }
+    if (NULL != field->buffer) {
+        cairo_surface_destroy(field->buffer);
+    }
+    g_object_unref(field->drawing_area);
+    /* field->drawing_area will be destroyed by its parent. */
+    g_free(field);
+}
+
+static void redraw(struct field * field)
+{
+    cairo_t * cr;
+    gchar * message;
+
+    g_return_if_fail(field->buffer);
+    draw_buffer(field);
+    cr = cairo_create(field->buffer);
+    if (MESSAGE_PAUSED == field->show_message) {
+        message = cdebconf_gtk_get_text(
+            field->tetris->fe, "cdebconf-gtk-tetris/paused", "Paused");
+        draw_message(field, cr, message);
+        g_free(message);
+    } else if (MESSAGE_GAME_OVER == field->show_message) {
+        message = cdebconf_gtk_get_text(
+            field->tetris->fe, "cdebconf-gtk-tetris/game-over", "Game Over");
+        draw_message(field, cr, message);
+        g_free(message);
+    }
+    cairo_destroy(cr);
+    draw_widget(field, 0, 0, field->pixel_width, field->pixel_height);
+    gtk_widget_queue_draw(field->drawing_area);
+}
+
+void redraw_field(struct tetris * tetris)
+{
+    redraw(tetris->field);
+}
+
+void show_message(struct tetris * tetris, MessageType message_type)
+{
+    struct field * field = tetris->field;
+
+    field->show_message = message_type;
+    redraw(field);
+}
+
+/* vim: et sw=4 si
+ */
diff --git a/packages/cdebconf-tetris/field.h b/packages/cdebconf-tetris/field.h
new file mode 100644
index 0000000..b688eba
--- /dev/null
+++ b/packages/cdebconf-tetris/field.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright © 2007 Jérémy Bobbio <lunar@debian.org>
+ *
+ * Based on Gnometris, written by J. Marcin Gorycki <marcin.gorycki@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _FIELD_H_
+#define _FIELD_H_
+
+#include <gtk/gtk.h>
+#include <cairo/cairo.h>
+
+struct field;
+
+#include "tetris.h"
+
+typedef enum {
+    MESSAGE_NONE,
+    MESSAGE_PAUSED,
+    MESSAGE_GAME_OVER
+} MessageType;
+
+struct field * create_field(struct tetris * tetris, GtkWidget * container);
+
+void destroy_field(struct field * field);
+
+void draw_background(cairo_t * cr);
+void draw_cell(cairo_t * cr, struct block * block, int x, int y);
+
+void redraw_field(struct tetris * tetris);
+
+void show_message(struct tetris * tetris, MessageType message_type);
+
+#endif /* !_FIELD_H_ */
+
+/* vim: et sw=4 si
+ */
diff --git a/packages/cdebconf-tetris/gtk-plugin-tetris.c b/packages/cdebconf-tetris/gtk-plugin-tetris.c
new file mode 100644
index 0000000..804b81b
--- /dev/null
+++ b/packages/cdebconf-tetris/gtk-plugin-tetris.c
@@ -0,0 +1,395 @@
+/*
+ * Copyright © 2007 Jérémy Bobbio <lunar@debian.org>
+ *
+ * Based on Gnometris, written by J. Marcin Gorycki <marcin.gorycki@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+#include <math.h>
+
+#include <cdebconf/frontend.h>
+#include <cdebconf/question.h>
+#include <cdebconf/cdebconf_gtk.h>
+
+/* Plugin entry point. */
+int cdebconf_gtk_handler_tetris(struct frontend * fe,
+                                struct question * question,
+                                GtkWidget * question_box);
+
+#include "field.h"
+#include "block_ops.h"
+#include "preview.h"
+#include "score.h"
+
+/* XXX: remove?
+#define BLOCK_SIZE 40 */
+
+/* XXX: remove?
+#define TILE_THRESHOLD 65 */
+
+static void toggle_pause(struct tetris * tetris)
+{
+    int paused = !tetris->paused;
+    gchar * label;
+
+    tetris->paused = paused;
+
+    show_message(tetris, paused ? MESSAGE_PAUSED : MESSAGE_NONE);
+
+    if (paused) {
+        label = cdebconf_gtk_get_text(
+            tetris->fe, "cdebconf-gtk-tetris/resume", "Resume");
+    } else {
+        label = cdebconf_gtk_get_text(
+            tetris->fe, "cdebconf-gtk-tetris/pause", "Pause");
+    }
+    gtk_button_set_label(GTK_BUTTON(tetris->pause_button), label);
+    g_free(label);
+}
+
+static void end_game(struct tetris * tetris)
+{
+    gchar * label;
+
+    if (0 != tetris->timeout_id) {
+        g_source_remove(tetris->timeout_id);
+        tetris->timeout_id = 0;
+    }
+    if (tetris->paused) {
+        toggle_pause(tetris);
+    }
+    gtk_widget_set_sensitive(tetris->pause_button, FALSE);
+    gtk_widget_set_sensitive(tetris->continue_button, TRUE);
+
+    tetris->blocknr_next = -1;
+    tetris->rot_next = -1;
+    preview_block(tetris->preview);
+    show_message(tetris, MESSAGE_GAME_OVER);
+    tetris->in_play = FALSE;
+
+    label = cdebconf_gtk_get_text(
+        tetris->fe, "cdebconf-gtk-tetris/new-game", "New game");
+    gtk_button_set_label(GTK_BUTTON(tetris->game_button), label);
+    g_free(label);
+}
+
+static void generate_new_block(struct tetris * tetris)
+{
+    if (generate_falling_block(tetris)) {
+        put_block_in_field(tetris, FALLING);
+        preview_block(tetris->preview);
+        tetris->one_pause = TRUE;
+    } else {
+        end_game(tetris);
+    }
+}
+
+static void manage_fallen(struct tetris * tetris);
+
+static gboolean handle_timeout(struct tetris * tetris)
+{
+    gboolean res;
+
+    if (tetris->paused) {
+        return TRUE;
+    }
+
+    if (tetris->one_pause) {
+        tetris->one_pause = FALSE;
+        redraw_field(tetris);
+    } else {
+        res = move_block_down(tetris);
+        redraw_field(tetris);
+        if (res) {
+            manage_fallen(tetris);
+        }
+    }
+    return TRUE;
+}
+
+static void generate_timer(struct tetris * tetris, int level)
+{
+    int intv;
+
+    g_assert(level > 0);
+
+    if (0 < tetris->timeout_id) {
+        g_source_remove(tetris->timeout_id);
+    }
+
+    intv = (int) (1000.0 * pow(0.8, level - 1));
+    if (10 >= intv) {
+        intv = 10;
+    }
+    tetris->timeout_id = g_timeout_add(intv, (GSourceFunc) handle_timeout,
+                                       tetris);
+}
+
+static void manage_fallen(struct tetris * tetris)
+{
+    int level_before;
+    int level_after;
+
+    falling_to_laying(tetris);
+
+    level_before = tetris->level;
+    level_after = score_lines(tetris, check_full_lines(tetris));
+    if (level_before != level_after) {
+        generate_timer(tetris, level_after);
+    }
+
+    if (is_field_empty(tetris)) {
+        score_last_line_bonus(tetris);
+    }
+
+    generate_new_block(tetris);
+}
+
+static void start_new_game(struct tetris * tetris)
+{
+    gchar * label;
+
+    if (tetris->timeout_id) {
+        g_source_remove(tetris->timeout_id);
+        tetris->timeout_id = 0;
+    }
+
+    tetris->in_play = TRUE;
+    tetris->paused = FALSE;
+
+    reset_score(tetris);
+
+    generate_timer(tetris, tetris->level);
+    empty_field(tetris);
+
+    generate_new_block(tetris);
+
+    gtk_widget_set_sensitive(tetris->pause_button, TRUE);
+    gtk_widget_set_sensitive(tetris->continue_button, FALSE);
+
+    label = cdebconf_gtk_get_text(
+        tetris->fe, "cdebconf-gtk-tetris/end-game", "End game");
+    gtk_button_set_label(GTK_BUTTON(tetris->game_button), label);
+    g_free(label);
+
+    /* will redraw the field. */
+    show_message(tetris, MESSAGE_NONE);
+}
+
+static gboolean handle_key_press(GtkWidget * widget, GdkEvent * event,
+                                 struct tetris * tetris)
+{
+    gboolean res = FALSE;
+    int keyval = ((GdkEventKey *) event)->keyval;
+
+    if (tetris->in_play && KEY_PAUSE == keyval) {
+        toggle_pause(tetris);
+        return TRUE;
+    }
+
+    if (0 == tetris->timeout_id || tetris->paused) {
+        return FALSE;
+    }
+
+    if (KEY_DOWN == keyval) {
+        if (!tetris->fast_fall && !tetris->one_pause) {
+            tetris->fast_fall = TRUE;
+            g_source_remove(tetris->timeout_id);
+            tetris->timeout_id = g_timeout_add(
+                10, (GSourceFunc) handle_timeout, tetris);
+        }
+        res = TRUE;
+    }
+
+    if (KEY_LEFT == keyval) {
+        res = move_block_left(tetris);
+        tetris->one_pause = FALSE;
+        res = TRUE;
+    } else if (KEY_RIGHT == keyval) {
+        res = move_block_right(tetris);
+        tetris->one_pause = FALSE;
+        res = TRUE;
+    } else if (KEY_UP == keyval) {
+        res = rotate_block(tetris, ROTATE_COUNTER_CLOCK_WISE);
+        tetris->one_pause = FALSE;
+        res = TRUE;
+    } else if (KEY_DROP == keyval) {
+        tetris->drop_block = TRUE;
+        drop_block(tetris);
+        manage_fallen(tetris);
+        res = TRUE;
+    }
+    if (res) {
+        redraw_field(tetris);
+    }
+    return res;
+}
+
+static gboolean handle_key_release(GtkWidget * widget, GdkEvent * event,
+                                   struct tetris * tetris)
+{
+    int keyval = ((GdkEventKey *) event)->keyval;
+
+    if (0 == tetris->timeout_id || tetris->paused) {
+        return FALSE;
+    }
+
+    if (KEY_DOWN == keyval) {
+        if (tetris->fast_fall) {
+            tetris->fast_fall = FALSE;
+            generate_timer(tetris, tetris->level);
+        }
+        return TRUE;
+    }
+    if (KEY_DROP == keyval) {
+        tetris->drop_block = FALSE;
+        return TRUE;
+    }
+    return FALSE;
+}
+
+static void handle_game_button(struct tetris * tetris)
+{
+    if (tetris->in_play) {
+        end_game(tetris);
+    } else {
+        start_new_game(tetris);
+    }
+}
+
+static void create_buttons(struct tetris * tetris)
+{
+    gchar * label;
+    GtkWidget * pause_button;
+    GtkWidget * game_button;
+    GtkWidget * continue_button;
+
+    label = cdebconf_gtk_get_text(
+        tetris->fe, "cdebconf-gtk-tetris/pause", "Pause");
+    pause_button = gtk_button_new_with_label(label);
+    g_free(label);
+    cdebconf_gtk_add_button(tetris->fe, pause_button);
+    cdebconf_gtk_set_button_secondary(tetris->fe, pause_button, TRUE);
+    gtk_widget_set_sensitive(pause_button, FALSE);
+    g_signal_connect_swapped(pause_button, "clicked",
+                             (GCallback) toggle_pause, tetris);
+    g_object_ref(pause_button);
+    tetris->pause_button = pause_button;
+
+    label = cdebconf_gtk_get_text(
+        tetris->fe, "cdebconf-gtk-tetris/new-game", "New game");
+    game_button = gtk_button_new_with_label(label);
+    g_free(label);
+    cdebconf_gtk_add_button(tetris->fe, game_button);
+    g_signal_connect_swapped(game_button, "clicked",
+                             (GCallback) handle_game_button, tetris);
+    g_object_ref(game_button);
+    tetris->game_button = game_button;
+
+    continue_button = cdebconf_gtk_create_continue_button(tetris->fe);
+    g_object_ref(continue_button);
+    tetris->continue_button = continue_button;
+}
+
+static GtkWidget * create_widget(struct tetris * tetris)
+{
+    GtkWidget * hb;
+    GtkWidget * vb1;
+    GtkWidget * vb2;
+
+    hb = gtk_hbox_new(FALSE, 0);
+
+    vb1 = gtk_vbox_new(FALSE, 0);
+    gtk_container_set_border_width(GTK_CONTAINER(vb1), 10);
+    tetris->field = create_field(tetris, vb1);
+    gtk_box_pack_start_defaults(GTK_BOX(hb), vb1);
+
+    vb2 = gtk_vbox_new(FALSE, 0);
+    gtk_container_set_border_width(GTK_CONTAINER(vb2), 10);
+    gtk_box_pack_end(GTK_BOX(hb), vb2, 0, 0, 0);
+
+    create_buttons(tetris);
+    tetris->preview = create_preview(tetris, vb2);
+    tetris->score_frame = create_score_frame(tetris, vb2);
+
+    return hb;
+}
+
+static void destroy_tetris(struct tetris * tetris)
+{
+    if (NULL == tetris) {
+        return;
+    }
+    destroy_field(tetris->field);
+    destroy_preview(tetris->preview);
+    destroy_score_frame(tetris->score_frame);
+    g_object_unref(tetris->widget);
+    g_free(tetris);
+}
+
+static void cleanup(struct question * question, struct tetris * tetris)
+{
+    GtkWidget * widget = tetris->widget;
+    GtkWidget * main_window = gtk_widget_get_toplevel(widget);
+
+    g_assert(!tetris->in_play);
+    g_signal_handlers_disconnect_by_func(
+        main_window, handle_key_press, tetris);
+    g_signal_handlers_disconnect_by_func(
+        main_window, handle_key_release, tetris);
+    destroy_tetris(tetris);
+}
+
+int cdebconf_gtk_handler_tetris(struct frontend * fe,
+                                struct question * question,
+                                GtkWidget * question_box)
+{
+    struct tetris * tetris;
+    GtkWidget * widget;
+    GtkWidget * main_window;
+
+    if (NULL == (tetris = g_malloc0(sizeof (struct tetris)))) {
+        g_warning("g_malloc0 failed.");
+        return DC_NOTOK;
+    }
+    tetris->fe = fe;
+    if (NULL == (widget = create_widget(tetris))) {
+        g_warning("create_widget failed.");
+        return DC_NOTOK;
+    }
+    g_object_ref(widget);
+    tetris->widget = widget;
+
+    cdebconf_gtk_add_common_layout(fe, question, question_box, widget);
+
+    main_window = gtk_widget_get_toplevel(widget);
+
+    g_signal_connect(main_window, "key_press_event",
+                     G_CALLBACK(handle_key_press), tetris);
+    g_signal_connect(main_window, "key_release_event",
+                     G_CALLBACK(handle_key_release), tetris);
+
+    gtk_widget_grab_focus(widget);
+    cdebconf_gtk_register_setter(fe, SETTER_FUNCTION(cleanup), question,
+                                 tetris);
+    return DC_OK;
+}
+
+/* vim: et sw=4 si
+ */
diff --git a/packages/cdebconf-tetris/linker-script b/packages/cdebconf-tetris/linker-script
new file mode 100644
index 0000000..2877829
--- /dev/null
+++ b/packages/cdebconf-tetris/linker-script
@@ -0,0 +1,6 @@
+{
+    global:
+        cdebconf_gtk_handler_tetris;
+    local:
+        *;
+};
diff --git a/packages/cdebconf-tetris/preview.c b/packages/cdebconf-tetris/preview.c
new file mode 100644
index 0000000..b1d0d2c
--- /dev/null
+++ b/packages/cdebconf-tetris/preview.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright © 2007 Jérémy Bobbio <lunar@debian.org>
+ *
+ * Based on Gnometris, written by J. Marcin Gorycki <marcin.gorycki@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <gtk/gtk.h>
+#include <cairo/cairo.h>
+
+#include "preview.h"
+
+#include "blocks.h"
+#include "field.h"
+
+#define PREVIEW_WIDTH 6
+#define PREVIEW_HEIGHT 6
+#define PREVIEW_SIZE 5
+
+struct preview {
+    struct tetris * tetris;
+    GtkWidget * widget;
+    gint pixel_width;
+    gint pixel_height;
+    gboolean enabled;
+    struct block blocks[PREVIEW_WIDTH][PREVIEW_HEIGHT];
+};
+
+static gboolean configure(GtkWidget * widget, GdkEventConfigure * event,
+                          struct preview * preview)
+{
+    preview->pixel_width = event->width;
+    preview->pixel_height = event->height;
+
+    return TRUE;
+}
+
+static gboolean expose(GtkWidget * widget, GdkEventExpose * event,
+                       struct preview * preview)
+{
+    cairo_t * cr;
+    cairo_surface_t * dst;
+    int x;
+    int y;
+
+    cr = gdk_cairo_create(widget->window);
+
+    if (!preview->enabled) {
+        cairo_scale(cr, 1.0 * widget->allocation.width / PREVIEW_WIDTH,
+                    1.0 * widget->allocation.height / PREVIEW_HEIGHT);
+        cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
+
+        cairo_set_source_rgb(cr, 0, 0, 0);
+        cairo_paint(cr);
+
+        cairo_set_source_rgb(cr, 0.8, 0.1, 0.1);
+        cairo_set_line_width(cr, 0.5);
+
+        cairo_move_to(cr, 1, 1);
+        cairo_line_to(cr, PREVIEW_WIDTH - 1, PREVIEW_HEIGHT - 1);
+        cairo_move_to(cr, PREVIEW_WIDTH - 1, 1);
+        cairo_line_to(cr, 1, PREVIEW_HEIGHT - 1);
+
+        cairo_stroke (cr);
+    } else {
+        dst = cairo_get_target(cr);
+        draw_background(cr);
+        cairo_scale(cr, 1.0 * preview->pixel_width / PREVIEW_WIDTH,
+                    1.0 * preview->pixel_height / PREVIEW_HEIGHT);
+        for (y = 0; y < PREVIEW_HEIGHT; y++) {
+            for (x = 0; x < PREVIEW_WIDTH; x++) {
+                draw_cell(cr, &preview->blocks[x][y], x, y);
+            }
+        }
+    }
+
+    cairo_destroy (cr);
+
+    return TRUE;
+}
+
+struct preview * create_preview(struct tetris * tetris, GtkWidget * container)
+{
+    struct preview * preview;
+    GtkWidget * widget;
+
+    if (NULL == (preview = g_malloc0(sizeof (struct preview)))) {
+        g_warning("g_malloc failed.");
+        return NULL;
+    }
+    preview->tetris = tetris;
+    preview->enabled = TRUE;
+
+    widget = gtk_drawing_area_new();
+
+    g_object_ref(widget);
+    preview->widget = widget;
+    /* FIXME: We should scale with the rest of the UI, but that requires
+     * changes to the widget layout - i.e. wrap the preview in an 
+     * fixed-aspect box. */
+    gtk_widget_set_size_request(
+        widget, PREVIEW_SIZE * 20, PREVIEW_SIZE * 20);
+
+    g_signal_connect(widget, "expose_event", G_CALLBACK(expose), preview);
+    g_signal_connect(widget, "configure_event",
+                     G_CALLBACK(configure), preview);
+
+    gtk_box_pack_start(GTK_BOX(container), widget, FALSE, FALSE, 0);
+
+    return preview;
+}
+
+void destroy_preview(struct preview * preview)
+{
+    if (NULL == preview) {
+        return;
+    }
+    g_object_unref(preview->widget);
+    /* preview->widget will be destroyed by its parent. */
+    g_free(preview);
+}
+
+void enable_preview(struct preview * preview, gboolean enabled)
+{
+    preview->enabled = enabled;
+    gtk_widget_queue_draw(preview->widget);
+}
+
+void preview_block(struct preview * preview)
+{
+    struct tetris * tetris = preview->tetris;
+    int blocknr = tetris->blocknr_next;
+    int blockrot = tetris->rot_next;
+    int x;
+    int y;
+
+    for (x = 1; x < PREVIEW_WIDTH - 1; x++) {
+        for (y = 1; y < PREVIEW_HEIGHT - 1; y++) {
+            if ((blocknr != -1) &&
+                BLOCK_TABLE[blocknr][blockrot][x - 1][y - 1]) {
+                preview->blocks[x][y].what = LAYING;
+                preview->blocks[x][y].color = blocknr % BLOCK_TYPES;
+            } else {
+                preview->blocks[x][y].what = EMPTY;
+            }
+        }
+    }
+    gtk_widget_queue_draw(preview->widget);
+}
+
+/* vim: et sw=4 si
+ */
diff --git a/packages/cdebconf-tetris/preview.h b/packages/cdebconf-tetris/preview.h
new file mode 100644
index 0000000..0b5f533
--- /dev/null
+++ b/packages/cdebconf-tetris/preview.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright © 2007 Jérémy Bobbio <lunar@debian.org>
+ *
+ * Based on Gnometris, written by J. Marcin Gorycki <marcin.gorycki@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _PREVIEW_H_
+#define _PREVIEW_H_
+
+#include <gtk/gtk.h>
+
+struct preview;
+
+#include "tetris.h"
+
+struct preview * create_preview(struct tetris * tetris, GtkWidget * container);
+
+void destroy_preview(struct preview * preview);
+
+void enable_preview(struct preview * preview, gboolean enabled);
+
+void preview_block(struct preview * preview);
+
+#endif /* !_PREVIEW_H_ */
+
+/* vim: et sw=4 si
+ */
diff --git a/packages/cdebconf-tetris/score.c b/packages/cdebconf-tetris/score.c
new file mode 100644
index 0000000..7039039
--- /dev/null
+++ b/packages/cdebconf-tetris/score.c
@@ -0,0 +1,182 @@
+/*
+ * Copyright © 2007 Jérémy Bobbio <lunar@debian.org>
+ *
+ * Based on Gnometris, written by J. Marcin Gorycki <marcin.gorycki@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "score.h"
+
+#include <gtk/gtk.h>
+
+struct score_frame {
+    GtkWidget * score_widget;
+    GtkWidget * lines_widget;
+    GtkWidget * level_widget;
+};
+
+struct score_frame * create_score_frame(struct tetris * tetris,
+                                        GtkWidget * container)
+{
+    struct score_frame * score_frame;
+    GtkWidget * table;
+    GtkWidget * score_label;
+    GtkWidget * score_widget;
+    GtkWidget * lines_label;
+    GtkWidget * lines_widget;
+    GtkWidget * level_label;
+    GtkWidget * level_widget;
+
+    if (NULL == (score_frame = g_malloc0(sizeof (struct score_frame)))) {
+        g_warning("g_malloc0 failed.");
+        return NULL;
+    }
+
+    table = gtk_table_new(3, 2, FALSE /* not homogeneous */);
+
+    score_label = gtk_label_new(_("Score:"));
+    gtk_misc_set_alignment(GTK_MISC(score_label), 0.0, 0.5);
+    gtk_table_attach_defaults(GTK_TABLE(table), score_label, 0, 1, 0, 1);
+
+    score_widget = gtk_label_new("0" /* XXX */);
+    gtk_misc_set_alignment(GTK_MISC(score_widget), 1.0, 0.5);
+    gtk_table_attach_defaults(GTK_TABLE(table), score_widget, 1, 2, 0, 1);
+    
+    g_object_ref(score_widget);
+    score_frame->score_widget = score_widget;
+
+    lines_label = gtk_label_new(_("Lines:"));
+    gtk_misc_set_alignment(GTK_MISC(lines_label), 0.0, 0.5);
+    gtk_table_attach_defaults(GTK_TABLE(table), lines_label, 0, 1, 1, 2);
+
+    lines_widget = gtk_label_new(NULL);
+    gtk_misc_set_alignment(GTK_MISC(lines_widget), 1.0, 0.5);
+    gtk_table_attach_defaults(GTK_TABLE(table), lines_widget, 1, 2, 1, 2);
+
+    g_object_ref(lines_widget);
+    score_frame->lines_widget = lines_widget;
+
+    level_label = gtk_label_new(_("Level:"));
+    gtk_misc_set_alignment(GTK_MISC(level_label), 0.0, 0.5);
+    gtk_table_attach_defaults(GTK_TABLE(table), level_label, 0, 1, 2, 3);
+
+    level_widget = gtk_label_new(NULL);
+    gtk_misc_set_alignment(GTK_MISC(level_widget), 1.0, 0.5);
+    gtk_table_attach_defaults(GTK_TABLE(table), level_widget, 1, 2, 2, 3);
+
+    g_object_ref(level_widget);
+    score_frame->level_widget = level_widget;
+
+    gtk_box_pack_end(GTK_BOX(container), table, TRUE, FALSE, 0);
+
+    return score_frame;
+}
+
+void destroy_score_frame(struct score_frame * score_frame)
+{
+    if (NULL == score_frame) {
+        return;
+    }
+    g_object_unref(score_frame->level_widget);
+    g_object_unref(score_frame->lines_widget);
+    g_object_unref(score_frame->score_widget);
+    /* widgets will be destroyed by their parents. */
+    g_free(score_frame);
+}
+
+static void set_score(struct tetris * tetris, int score)
+{
+    struct score_frame * score_frame = tetris->score_frame;
+    gchar * s;
+
+    tetris->score = score;
+    s = g_strdup_printf("%7d", tetris->score);
+    gtk_label_set_text(GTK_LABEL(score_frame->score_widget), s);
+    g_free(s);
+}
+
+static void inc_score(struct tetris * tetris, int increment)
+{
+    set_score(tetris, tetris->score + increment);
+}
+
+void score_last_line_bonus(struct tetris * tetris)
+{
+    inc_score(tetris, 10000 * tetris->level);
+}
+
+static void set_level(struct tetris * tetris, int level)
+{
+    struct score_frame * score_frame = tetris->score_frame;
+    gchar * s;
+
+    tetris->level = level;
+    s = g_strdup_printf("%7d", tetris->level);
+    gtk_label_set_text(GTK_LABEL(score_frame->level_widget), s);
+    g_free(s);
+}
+
+static void set_lines(struct tetris * tetris, int lines)
+{
+    struct score_frame * score_frame = tetris->score_frame;
+    gchar * s;
+
+    tetris->lines = lines;
+    s = g_strdup_printf("%7d", tetris->lines);
+    gtk_label_set_text(GTK_LABEL(score_frame->lines_widget), s);
+    g_free(s);
+}
+
+int score_lines(struct tetris * tetris, int newlines)
+{
+    int level = tetris->level;
+    int linescore = 0;
+
+    switch (newlines) {
+        case 0:
+            return level;
+        case 1:
+            linescore = 40;
+            break;
+        case 2:
+            linescore = 100;
+            break;
+        case 3:
+            linescore = 300;
+            break;
+        case 4:
+            linescore = 1200;
+            break;
+    }
+    inc_score(tetris, level * linescore);
+
+    /* check the level */
+    set_lines(tetris, tetris->lines + newlines);
+    set_level(tetris, STARTING_LEVEL + tetris->lines / 10);
+
+    return level;
+}
+
+void reset_score(struct tetris * tetris)
+{
+    set_lines(tetris, 0);
+    set_score(tetris, 0);
+    set_level(tetris, STARTING_LEVEL);
+}
+
+/* vim: et sw=4 si
+ */
diff --git a/packages/cdebconf-tetris/score.h b/packages/cdebconf-tetris/score.h
new file mode 100644
index 0000000..cc3bcc0
--- /dev/null
+++ b/packages/cdebconf-tetris/score.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright © 2007 Jérémy Bobbio <lunar@debian.org>
+ *
+ * Based on Gnometris, written by J. Marcin Gorycki <marcin.gorycki@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _SCORE_H_
+#define _SCORE_H_
+
+#include <gtk/gtk.h>
+
+struct score_frame;
+
+#include "tetris.h"
+
+struct score_frame * create_score_frame(struct tetris * tetris,
+                                        GtkWidget * container);
+
+void destroy_score_frame(struct score_frame * score_frame);
+
+int score_lines(struct tetris * tetris, int newlines);
+
+void score_last_line_bonus(struct tetris * tetris);
+
+void reset_score(struct tetris * tetris);
+
+#endif /* !_SCORE_H_ */
+
+/* vim: et sw=4 si
+ */
diff --git a/packages/cdebconf-tetris/tetris.h b/packages/cdebconf-tetris/tetris.h
new file mode 100644
index 0000000..d19d2d5
--- /dev/null
+++ b/packages/cdebconf-tetris/tetris.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright © 2007 Jérémy Bobbio <lunar@debian.org>
+ *
+ * Based on Gnometris, written by J. Marcin Gorycki <marcin.gorycki@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _TETRIS_H_
+#define _TETRIS_H_
+
+#include <glib.h>
+
+#include <cdebconf/frontend.h>
+
+struct tetris;
+
+#include "blocks.h"
+#include "score.h"
+#include "preview.h"
+
+#define LINES 20
+#define COLUMNS 11
+
+#define STARTING_LEVEL 1
+
+#define KEY_PAUSE GDK_p
+#define KEY_DOWN GDK_Down
+#define KEY_LEFT GDK_Left
+#define KEY_RIGHT GDK_Right
+#define KEY_UP GDK_Up
+#define KEY_DROP GDK_space
+
+struct tetris {
+    struct frontend * fe;
+    struct field * field;
+    struct preview * preview;
+    GtkWidget * widget;
+    GtkWidget * pause_button;
+    GtkWidget * game_button;
+    GtkWidget * continue_button;
+    struct score_frame * score_frame;
+    gboolean paused;
+    int timeout_id;
+    gboolean one_pause;
+    gboolean in_play;
+    gboolean fast_fall;
+    gboolean drop_block;
+    int level;
+    int score;
+    int lines;
+    int blocknr_next;
+    int rot_next;
+    int rot;
+    int blocknr;
+    int posx;
+    int posy;
+    struct block blocks[COLUMNS][LINES];
+};
+
+#endif /* !_TETRIS_H_ */
+
+/* vim: et sw=4 si
+ */

-- 
Jérémy Bobbio                        .''`. 
lunar@debian.org                    : :Ⓐ  :  # apt-get install anarchism
                                    `. `'` 
                                      `-   

Attachment: signature.asc
Description: Digital signature


Reply to: