summaryrefslogtreecommitdiff
path: root/gnome-about
diff options
context:
space:
mode:
authorVincent Untz <vuntz@gnome.org>2007-11-12 22:08:41 +0000
committerVincent Untz <vuntz@src.gnome.org>2007-11-12 22:08:41 +0000
commit338bccce61a3550a6168f557ccb5abfb8699db74 (patch)
treec4b20c5761397fd3efbf16321bd4304430f6aca9 /gnome-about
parent660193fd7fcc065a6ae58e96a97f4e0fe092b52b (diff)
downloadgnome-desktop-338bccce61a3550a6168f557ccb5abfb8699db74.tar.gz
Rewrite of gnome-about in python. It's now much better, and it's
2007-11-12 Vincent Untz <vuntz@gnome.org> Rewrite of gnome-about in python. It's now much better, and it's accessible. Closes a lot of bugs, see bug #481585. Based on work by Guillaume Seguin <guillaume@segu.in> * configure.in: remove gnomecanvas dependency, and check for python * gnome-about/Makefile.am: updated * gnome-about/contributors.[ch]: killed * gnome-about/gnome-about.c: killed * gnome-about/gnome-about.in: new file svn path=/trunk/; revision=4921
Diffstat (limited to 'gnome-about')
-rw-r--r--gnome-about/Makefile.am34
-rw-r--r--gnome-about/contributors.c222
-rw-r--r--gnome-about/contributors.h12
-rw-r--r--gnome-about/gnome-about.c1264
-rw-r--r--gnome-about/gnome-about.in1007
5 files changed, 1022 insertions, 1517 deletions
diff --git a/gnome-about/Makefile.am b/gnome-about/Makefile.am
index 9cc305ca..e7031edb 100644
--- a/gnome-about/Makefile.am
+++ b/gnome-about/Makefile.am
@@ -1,20 +1,16 @@
-INCLUDES = \
- $(WARN_CFLAGS) \
- $(DISABLE_DEPRECATED_CFLAGS) \
- $(GNOME_ABOUT_CFLAGS) \
- $(DISABLE_DEPRECATED) \
- -DGNOMELOCALEDIR=\""$(prefix)/$(DATADIRNAME)/locale\"" \
- -DGNOME_ICONDIR=\""$(datadir)/pixmaps\"" \
- -DDATADIR=\"$(datadir)/gnome-about\"
-
-LDADD = $(GNOME_ABOUT_LIBS)
-
-bin_PROGRAMS = gnome-about
-
-gnome_about_SOURCES = \
- gnome-about.c \
- contributors.c \
- contributors.h
+bin_SCRIPTS = gnome-about
+
+gnome-about: gnome-about.in Makefile
+ sed \
+ -e s!\@PYTHON\@!@PYTHON@! \
+ -e s!\@GETTEXT_PACKAGE\@!@GETTEXT_PACKAGE@! \
+ -e s!\@LOCALEDIR\@!$(datadir)/locale! \
+ -e s!\@DATADIR\@!$(datadir)/gnome-about! \
+ -e s!\@ICONDIR\@!$(datadir)/pixmaps! \
+ -e s!\@PACKAGE_NAME\@!$(PACKAGE_NAME)! \
+ -e s!\@PACKAGE_VERSION\@!$(PACKAGE_VERSION)! \
+ < $< > $@
+ chmod a+x $@
@INTLTOOL_DESKTOP_RULE@
@@ -25,11 +21,11 @@ desktop_DATA = $(desktop_in_files:.desktop.in=.desktop)
aboutdir = $(datadir)/gnome-about
about_DATA = gnome-64.png contributors.list foundation-members.list
-EXTRA_DIST = $(about_DATA)
+EXTRA_DIST = $(about_DATA) gnome-about.in
SUBDIRS = headers
-CLEANFILES = gnome-about.desktop
+CLEANFILES = gnome-about.desktop gnome-about
check:
test -s $(top_srcdir)/gnome-about/foundation-members.list
diff --git a/gnome-about/contributors.c b/gnome-about/contributors.c
deleted file mode 100644
index b8a91375..00000000
--- a/gnome-about/contributors.c
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * contributors.c:
- *
- * Copyright (C) 2007 Vincent Untz
- *
- * 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; see the file COPYING. If not, write to the Free
- * Software Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Authors:
- * Vincent Untz <vuntz@gnome.org>
- *
- * generate_randomness() comes from gnome-about.c
- */
-
-
-#include <config.h>
-
-#include <string.h>
-
-#include <glib.h>
-#include <glib/gi18n.h>
-
-#include <libgnome/gnome-program.h>
-
-#include "contributors.h"
-
-static int num_old_contributors;
-static int num_foundation_contributors;
-static int num_total;
-static int *contrib_order = NULL;
-
-#define OLD_CONTRIBUTORS_FILE "contributors.list"
-#define FOUNDATION_CONTRIBUTORS_FILE "foundation-members.list"
-static char **old_contributors = NULL;
-static char **foundation_contributors = NULL;
-static char *translated_contributors[] = {
- N_("The Mysterious GEGL"),
- N_("The Squeaky Rubber GNOME"),
- N_("Wanda The GNOME Fish")
-};
-
-static void
-generate_randomness (void)
-{
- int i;
- int random_number;
- int tmp;
- GRand *generator;
-
- if (contrib_order != NULL)
- g_free (contrib_order);
-
- generator = g_rand_new ();
-
- contrib_order = g_malloc (num_total * sizeof (int));
-
- for (i = 0; i < num_total; i++)
- contrib_order[i]=i;
-
- for (i = 0; i < num_total; i++) {
- random_number = g_rand_int_range (generator, i, num_total);
- tmp = contrib_order[i];
- contrib_order[i] = contrib_order[random_number];
- contrib_order[random_number] = tmp;
- }
-
- g_rand_free (generator);
-}
-
-const char *
-contributors_get (int i)
-{
- int real;
-
- g_assert (contrib_order != NULL);
-
- real = i % (num_total);
-
- if (contrib_order[real] < G_N_ELEMENTS (translated_contributors))
- return _(translated_contributors[contrib_order[real]]);
- else if (contrib_order[real] < G_N_ELEMENTS (translated_contributors)
- + num_old_contributors)
- return old_contributors[contrib_order[real] -
- G_N_ELEMENTS (translated_contributors)];
- else if (contrib_order[real] < G_N_ELEMENTS (translated_contributors)
- + num_old_contributors
- + num_foundation_contributors)
- return foundation_contributors[contrib_order[real]
- - G_N_ELEMENTS (translated_contributors)
- - num_old_contributors];
- else
- g_assert_not_reached ();
-}
-
-
-static void
-contributors_read_from_file (const char *file,
- char ***contributors,
- int *contributors_nb)
-{
- char *contents;
- GError *error;
- int i;
- char **contributors_array;
- GList *contributors_l;
- GList *l;
-
- g_assert (contributors != NULL);
- g_assert (contributors_nb != NULL);
- g_assert (*contributors == NULL);
-
- error = NULL;
- if (!g_file_get_contents (file, &contents, NULL, &error)) {
- g_printerr ("Cannot read list of contributors: %s\n",
- error->message);
- g_error_free (error);
- return;
- }
-
- *contributors_nb = 0;
- *contributors = NULL;
-
- contributors_l = NULL;
- contributors_array = g_strsplit (contents, "\n", -1);
- /* we could stop here, and directly use contributors_array, but we need
- * to check that the strings are valid UTF-8 */
-
- g_free (contents);
-
- if (contributors_array[0] == NULL ||
- strcmp (contributors_array[0],
- "# gnome-about contributors - format 1") != 0) {
- g_strfreev (contributors_array);
- return;
- }
-
- for (i = 0; contributors_array[i] != NULL; i++) {
- if (!g_utf8_validate (contributors_array[i], -1, NULL) ||
- contributors_array[i][0] == '\0' ||
- contributors_array[i][0] == '#')
- continue;
-
- contributors_l = g_list_prepend (contributors_l,
- g_strdup (contributors_array[i]));
- (*contributors_nb)++;
- }
- g_strfreev (contributors_array);
-
- *contributors = g_malloc ((*contributors_nb + 1) * sizeof (char *));
-
- for (i = 0, l = contributors_l; l != NULL; l = l->next, i++)
- (*contributors)[i] = l->data;
- g_list_free (contributors_l);
-
- /* we want to use g_strfreev */
- (*contributors)[i] = NULL;
-}
-
-static void
-contributors_read (const char *filename,
- char ***contributors,
- int *contributors_nb)
-{
- char *file;
-
- file = gnome_program_locate_file (NULL,
- GNOME_FILE_DOMAIN_APP_DATADIR,
- filename,
- TRUE, NULL);
- if (!file)
- return;
-
- contributors_read_from_file (file, contributors, contributors_nb);
- num_total += *contributors_nb;
-
- g_free (file);
-}
-
-void
-contributors_free (void)
-{
- if (contrib_order)
- g_free (contrib_order);
- contrib_order = NULL;
-
- if (old_contributors)
- g_strfreev (old_contributors);
- old_contributors = NULL;
-
- if (foundation_contributors)
- g_strfreev (foundation_contributors);
- foundation_contributors = NULL;
-}
-
-void
-contributors_init (void)
-{
- num_old_contributors = 0;
- num_foundation_contributors = 0;
- num_total = G_N_ELEMENTS (translated_contributors);
-
- contributors_read (OLD_CONTRIBUTORS_FILE,
- &old_contributors,
- &num_old_contributors);
- contributors_read (FOUNDATION_CONTRIBUTORS_FILE,
- &foundation_contributors,
- &num_foundation_contributors);
-
- generate_randomness ();
-}
diff --git a/gnome-about/contributors.h b/gnome-about/contributors.h
deleted file mode 100644
index dfa6e85c..00000000
--- a/gnome-about/contributors.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef CONTRIBUTORS_H
-#define CONTRIBUTORS_H
-
-G_BEGIN_DECLS
-
-const char *contributors_get (int i);
-void contributors_free (void);
-void contributors_init (void);
-
-G_END_DECLS
-
-#endif /* CONTRIBUTORS_H */
diff --git a/gnome-about/gnome-about.c b/gnome-about/gnome-about.c
deleted file mode 100644
index 3739cfc5..00000000
--- a/gnome-about/gnome-about.c
+++ /dev/null
@@ -1,1264 +0,0 @@
-/* gnome-about.c: Super Funky Dope gnome about window.
- *
- * Copyright (C) 2002, Sun Microsystems, Inc.
- * Copyright (C) 2003, Kristian Rietveld
- *
- * 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.
- *
- * Authors:
- * Glynn Foster <glynn.foster@sun.com>
- * Mark McLoughlin <mark@skynet.ie>
- * Kristian Rietveld <kris@gtk.org>
- * Jeff Waugh <jdub@perkypants.org>
- * Malcolm Tredinnick <malcolm@commsecure.com.au>
- */
-
-#include <config.h>
-
-#include <glib/gi18n.h>
-
-#include <libgnome/libgnome.h>
-#include <libgnomeui/libgnomeui.h>
-#include <libgnomecanvas/libgnomecanvas.h>
-
-/* for parsing gnome-version.xml */
-#include <libxml/tree.h>
-#include <libxml/parser.h>
-
-/* for readdir */
-#include <sys/types.h>
-#include <string.h>
-
-#include <dirent.h>
-#include <errno.h>
-#include <time.h>
-
-#include "contributors.h"
-
-/* pick some good defaults */
-static gdouble canvas_width = 550.0;
-static gdouble canvas_height = 350.0;
-
-
-static char **introduction_messages = NULL;
-static GnomeCanvasItem *subheader = NULL;
-static gdouble version_info_height = 0.0;
-static gint contrib_i = 0;
-
-/* funky animations */
-typedef struct {
- GnomeCanvas *canvas;
- GnomeCanvasItem *item;
-} AnimationData;
-
-/* contributors */
-static gboolean display_contributors (gpointer data);
-
-static gboolean
-animate_contributor (gpointer data)
-{
- AnimationData *ani_data = (AnimationData *)data;
- gboolean before_middle;
- gdouble tmp, tmp2, y;
- guint color, tmpcolor;
- gdouble size;
-
- g_object_get (ani_data->item,
- "text_width", &tmp,
- "text_height", &tmp2,
- "fill_color_rgba", &color,
- "size_points", &size,
- NULL);
-
- y = ani_data->item->parent->y1;
-
- /* ugh */
- g_object_set (GNOME_CANVAS_GROUP (ani_data->item->parent)->item_list->data,
- "x1", -1.0 * (tmp / 2.0 + 3.0),
- "y1", -1.0 * (tmp2 / 2.0 + 3.0),
- "x2", tmp / 2.0 + 3.0,
- "y2", tmp2 / 2.0 + 3.0,
- NULL);
-
- before_middle = 130.0 + ((canvas_height - 130.0 - version_info_height - tmp2) / 2.0) < y;
-
- /* update the color */
- tmpcolor = color & 0xff;
- tmpcolor += before_middle ? -6 : 6;
- size += before_middle ? 1.0 : -1.0;
- size = MAX (0.0, size);
- color = GNOME_CANVAS_COLOR_A (tmpcolor, tmpcolor, tmpcolor, tmpcolor);
-
- g_object_set (ani_data->item,
- "fill_color_rgba", color,
- "size_points", size,
- NULL);
-
- /* move damnit!! */
- gnome_canvas_item_move (ani_data->item->parent, 0.0, -2.5);
-
- y -= 2.5;
-
- gnome_canvas_update_now (ani_data->canvas);
-
- /* time for a new one ??? */
- if (y <= 130.0) {
- display_contributors (ani_data->canvas);
- g_free (ani_data);
- return FALSE;
- }
-
- return TRUE;
-}
-
-static gboolean
-canvas_button_press_event (GtkWidget *widget,
- GdkEventButton *event,
- gpointer user_data)
-{
- gchar *text;
-
- /* the links should still be clickable */
- if (event->y <= 80.0)
- return FALSE;
-
- text = g_strdup_printf ("<b>%s</b>", contributors_get (contrib_i));
- contrib_i++;
-
- gnome_canvas_item_set (GNOME_CANVAS_ITEM (user_data),
- "markup", text,
- NULL);
- g_free (text);
-
- return TRUE;
-}
-
-static gboolean
-display_contributors (gpointer data)
-{
- GnomeCanvas *canvas = GNOME_CANVAS (data);
- AnimationData *ani_data;
-
- static GnomeCanvasItem *contributor = NULL;
- /* FIXME: this is a workaround for a libgnomecanvas bug. See bug #329165.
- * When removing it, we should not forget to remove the "ugh" part of
- * animate_contributor() */
- static GnomeCanvasItem *contributor_rect = NULL;
- static GnomeCanvasItem *contributor_text = NULL;
-
- if (!contributor) {
- gchar *text;
-
- contributor =
- gnome_canvas_item_new (GNOME_CANVAS_GROUP (canvas->root),
- gnome_canvas_group_get_type (),
- NULL);
-
- contributor_rect =
- gnome_canvas_item_new (GNOME_CANVAS_GROUP (contributor),
- gnome_canvas_rect_get_type (),
- "fill_color", "White",
- NULL);
-
- text = g_strdup_printf ("<b>%s</b>", contributors_get (contrib_i));
- contributor_text =
- gnome_canvas_item_new (GNOME_CANVAS_GROUP (contributor),
- gnome_canvas_text_get_type (),
- "markup", text,
- "anchor", GTK_ANCHOR_CENTER,
- "fill_color_rgba", 0xffffffff,
- NULL);
- g_free (text);
-
- g_signal_connect (canvas, "button_press_event",
- G_CALLBACK (canvas_button_press_event),
- contributor_text);
-
- gnome_canvas_item_move (contributor,
- canvas_width / 2.0,
- canvas_height - version_info_height);
- } else {
- gchar *text;
-
- text = g_strdup_printf ("<b>%s</b>", contributors_get (contrib_i));
- gnome_canvas_item_set (contributor_text,
- "markup", text,
- "fill_color_rgba", 0xffffffff,
- "size_points", 0.0,
- NULL);
- g_free (text);
-
- gnome_canvas_item_move (contributor, 0.0,
- canvas_height - version_info_height - contributor->y1);
- }
-
- ani_data = g_new0 (AnimationData, 1);
-
- ani_data->canvas = canvas;
- ani_data->item = contributor_text;
-
- g_timeout_add (75, animate_contributor, ani_data);
- contrib_i++;
-
- return FALSE;
-}
-
-/* subheader */
-static gboolean
-display_subheader (gpointer data)
-{
- GnomeCanvas *canvas = GNOME_CANVAS (data);
- static gboolean first = TRUE;
-
- if (first) {
- guint color = GNOME_CANVAS_COLOR_A (0xff, 0xff, 0xff, 0xff);
-
- gnome_canvas_item_set (subheader,
- "fill_color_rgba", color,
- NULL);
- gnome_canvas_item_show (subheader);
- gnome_canvas_update_now (canvas);
-
- first = FALSE;
- } else {
- guint color;
- guint tmp;
-
- g_object_get (subheader, "fill_color_rgba", &color, NULL);
- tmp = color & 0xFF;
-
- if (tmp < 15) {
- /* make sure it's black */
- color = GNOME_CANVAS_COLOR_A (0x0, 0x0, 0x0, 0x0);
- g_object_set (subheader,
- "fill_color_rgba", color, NULL);
- gnome_canvas_update_now (canvas);
-
- display_contributors (canvas);
-
- return FALSE;
- }
-
- tmp -= 15;
- color = GNOME_CANVAS_COLOR_A (tmp, tmp, tmp, tmp);
- g_object_set (subheader, "fill_color_rgba", color, NULL);
- gnome_canvas_update_now (canvas);
- }
-
- return TRUE;
-}
-
-/* introduction messages */
-static gboolean display_introduction_message (gpointer data);
-
-static gboolean
-animate_text (gpointer data)
-{
- AnimationData *ani_data = (AnimationData *)data;
-
- gnome_canvas_item_move (ani_data->item->parent, 0.0, -10.0);
-
- if (ani_data->item->parent->y1 <= 120.0) {
- g_timeout_add_seconds (5,
- display_introduction_message,
- ani_data->canvas);
- g_free (ani_data);
- return FALSE;
- }
-
- return TRUE;
-}
-
-static gboolean
-display_introduction_message (gpointer data)
-{
- GnomeCanvas *canvas = GNOME_CANVAS (data);
- AnimationData *ani_data;
-
- static GnomeCanvasItem *intro = NULL;
- /* FIXME: this is a workaround for a libgnomecanvas bug. See bug #329165. */
- static GnomeCanvasItem *intro_rect = NULL;
- static GnomeCanvasItem *intro_text = NULL;
- static gint intro_i = 0;
-
- if (!introduction_messages || !introduction_messages[intro_i]) {
- /* just hide the intro now, the canvas will
- * take care of disposing it (if we do an _unref here
- * it crashes for some reason, too lazy to find out why)
- */
- if (intro)
- gnome_canvas_item_hide (GNOME_CANVAS_ITEM (intro));
- intro = NULL;
-
- g_timeout_add (100, display_subheader, canvas);
- return FALSE;
- }
-
- if (!intro_text) {
- gdouble tmp;
-
- intro =
- gnome_canvas_item_new (GNOME_CANVAS_GROUP (canvas->root),
- gnome_canvas_group_get_type (),
- NULL);
-
- intro_rect =
- gnome_canvas_item_new (GNOME_CANVAS_GROUP (intro),
- gnome_canvas_rect_get_type (),
- "fill_color", "White",
- "x1", -4.0,
- "y1", -4.0,
- "x2", 304.0,
- "y2", 84.0,
- NULL);
-
- intro_text =
- gnome_canvas_item_new (GNOME_CANVAS_GROUP (intro),
- gnome_canvas_rich_text_get_type (),
- "text", introduction_messages[intro_i],
- "editable", FALSE,
- /* FIXME */
- "width", 300.0,
- "height", 80.0,
- "grow_height", TRUE,
- "cursor_visible", FALSE,
- NULL);
-
- g_object_get (intro_text, "height", &tmp, NULL);
- gnome_canvas_item_move (intro,
- (canvas_width - 300.0) / 2.0,
- canvas_height - version_info_height - tmp);
- gnome_canvas_update_now (canvas);
- } else {
- gdouble y;
- gdouble tmp;
-
- gnome_canvas_item_set (intro_text,
- "text", introduction_messages[intro_i],
- NULL);
-
- g_object_get (intro_text, "height", &tmp, NULL);
- y = intro->y1;
-
- gnome_canvas_item_move (intro,
- 0.0,
- canvas_height - version_info_height - y - tmp);
- gnome_canvas_update_now (canvas);
- }
-
- ani_data = g_new0 (AnimationData, 1);
-
- ani_data->canvas = canvas;
- ani_data->item = intro_text;
-
- g_timeout_add (15, animate_text, ani_data);
- intro_i++;
-
- return FALSE;
-}
-
-static void
-start_animations (GtkWidget *widget,
- gpointer user_data)
-{
- display_introduction_message (GNOME_CANVAS (widget));
-}
-
-/* loading funky stuff */
-static void
-show_error_dialog (const gchar *message)
-{
- GtkWidget *dialog;
-
- dialog = gtk_message_dialog_new (NULL,
- GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_MESSAGE_ERROR,
- GTK_BUTTONS_CLOSE,
- message);
-
- gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
- gtk_widget_show (dialog);
-
- gtk_dialog_run (GTK_DIALOG (dialog));
-
- gtk_widget_destroy (dialog);
-}
-
-static GdkPixbuf *
-load_random_header (void)
-{
- GdkPixbuf *pixbuf;
- GList *files = NULL, *i;
- GError *error = NULL;
- gchar *text;
- gchar *directory;
- gint selected;
-
- DIR *dir;
- struct dirent *d;
-
- directory = gnome_program_locate_file (NULL,
- GNOME_FILE_DOMAIN_APP_DATADIR,
- "headers",
- TRUE, NULL);
-
- if (!directory) {
- show_error_dialog (_("Could not locate the directory with header images."));
-
- return NULL;
- }
-
- dir = opendir (directory);
- if (!dir) {
- char *message;
-
- message = g_strdup_printf (_("Failed to open directory with header images: %s"),
- strerror (errno));
- show_error_dialog (message);
- g_free (message);
- g_free (directory);
-
- return NULL;
- }
-
- while ((d = readdir (dir))) {
- if (g_str_has_suffix (d->d_name, ".gif") ||
- g_str_has_suffix (d->d_name, ".png"))
- files = g_list_prepend (files, g_strdup (d->d_name));
- }
-
- closedir (dir);
-
- selected = g_random_int_range (0, g_list_length (files));
-
- text = g_strdup_printf ("%s/%s", directory,
- (char *)g_list_nth_data (files, selected));
- g_free (directory);
-
- pixbuf = gdk_pixbuf_new_from_file (text, &error);
- g_free (text);
-
- for (i = files; i; i = i->next)
- g_free (i->data);
- g_list_free (files);
-
- if (error) {
- char *message;
-
- message = g_strdup_printf (_("Unable to load header image: %s"),
- error->message);
- show_error_dialog (message);
-
- g_free (message);
- g_error_free (error);
-
- return NULL;
- }
-
- return pixbuf;
-}
-
-static GdkPixbuf *
-load_logo (void)
-{
- gchar *file;
- GdkPixbuf *pixbuf;
- GError *error = NULL;
-
- file = gnome_program_locate_file (NULL,
- GNOME_FILE_DOMAIN_APP_DATADIR,
- "gnome-64.png",
- TRUE, NULL);
- if (!file) {
- show_error_dialog (_("Could not locate the GNOME logo."));
-
- return NULL;
- }
-
- pixbuf = gdk_pixbuf_new_from_file (file, &error);
- if (error) {
- char *message;
-
- message = g_strdup_printf (_("Unable to load '%s': %s"),
- file,
- error->message);
- g_free (file);
- show_error_dialog (message);
-
- g_free (message);
- g_error_free (error);
-
- return NULL;
- }
-
- g_free (file);
-
- return pixbuf;
-}
-
-/* href item impl */
-typedef struct {
- GnomeCanvasItem *item;
-
- const gchar *text;
- const gchar *url;
-} HRefItem;
-
-static gboolean
-href_item_event_callback (GnomeCanvasItem *item,
- GdkEvent *event,
- gpointer user_data)
-{
- HRefItem *href = (HRefItem *) user_data;
-
- switch (event->type) {
- case GDK_ENTER_NOTIFY: {
- GdkCursor *cursor;
-
- cursor = gdk_cursor_new (GDK_HAND2);
-
- gdk_window_set_cursor (GTK_WIDGET (item->canvas)->window, cursor);
- gdk_cursor_unref (cursor);
- }
- break;
- case GDK_LEAVE_NOTIFY:
- gdk_window_set_cursor (GTK_WIDGET (item->canvas)->window, NULL);
- break;
-
- case GDK_BUTTON_PRESS: {
- GError *error= NULL;
-
- gnome_url_show (href->url, &error);
- if (error) {
- char *message;
-
- message = g_strdup_printf (_("Could not open the address \"%s\": %s"),
- href->url, error->message);
- show_error_dialog (message);
-
- g_free (message);
- g_error_free (error);
- }
-
- return TRUE;
- }
-
- default:
- break;
- }
-
- return FALSE;
-}
-
-static HRefItem *
-href_item_new (GnomeCanvasGroup *group,
- const gchar *text,
- const gchar *url,
- gdouble *current_x,
- gdouble *current_y)
-{
- HRefItem *item;
- gdouble tmp;
-
- item = g_new0 (HRefItem, 1);
- item->text = g_strdup (text);
- item->url = g_strdup (url);
-
- item->item =
- gnome_canvas_item_new (group,
- gnome_canvas_text_get_type (),
- "text", text,
- "anchor", GTK_ANCHOR_NW,
- "x", *current_x,
- "y", *current_y,
- "underline", PANGO_UNDERLINE_SINGLE,
- "weight", PANGO_WEIGHT_BOLD,
- "fill_color", "#000000",
- NULL);
- g_signal_connect (item->item, "event",
- G_CALLBACK (href_item_event_callback), item);
-
- g_object_get (item->item, "text_width", &tmp, NULL);
- *current_x += tmp + 5.0;
-
- return item;
-}
-
-static GnomeCanvasItem *
-create_dot (GnomeCanvasGroup *group,
- gdouble *current_x,
- gdouble *current_y,
- gdouble dot_delta)
-{
- GnomeCanvasItem *item;
- gdouble tmp;
-
- item = gnome_canvas_item_new (group,
- gnome_canvas_text_get_type (),
- "text", ".",
- "anchor", GTK_ANCHOR_NW,
- "x", *current_x,
- "y", *current_y - dot_delta,
- "weight", PANGO_WEIGHT_BOLD,
- "fill_color", "#000000",
- NULL);
-
- g_object_get (item, "text_width", &tmp, NULL);
- *current_x += tmp + 5.0;
-
- return item;
-}
-
-/* the canvas */
-static char *
-strip_newlines (const char *str)
-{
- char **strv;
- char *tmp;
-
- if (!str)
- return NULL;
-
- strv = g_strsplit (str, "\n", -1);
- tmp = g_strjoinv (" ", strv);
- g_strfreev (strv);
- tmp = g_strchug (tmp);
-
- return tmp;
-}
-
-/* FIXME: This could possibly be done more smoothly. The locale matching stuff
- * needs to be abstracted out, since it must be useful in a number of places. */
-
-/* The language selection stuff here is not blindingly efficient, but it is
- * only done once for a small number of paragraphs, so I (Malcolm) think we can
- * just pay the penalty rather than going for something more complex.
- *
- * The problem we are solving here is, for each paragraph, find the translated
- * version that matches the highest preference possible from amongst the user's
- * LC_MESSAGES settings. Note that the translated paragraphs may not appear in
- * the same order as the LC_MESSAGE preferences, so a certain amount of messing
- * around is required (in particular, we cannot quit after finding the first
- * match).
- */
-
-/* FIXME: this code is atrocious */
-
-static void
-get_description_messages (xmlNodePtr node)
-{
- xmlNodePtr paras;
- GSList *list = NULL, *l;
- const char * const * langs;
- gint i;
- gboolean started = FALSE;
- char *best_value = NULL;
-
- langs = g_get_language_names ();
- paras = node->children;
-
- while (paras) {
- while (paras) {
- xmlChar *value = xmlNodeGetContent (paras);
- char *tmp;
- xmlChar *cur, *best = NULL;
-
- if (paras->type == XML_ELEMENT_NODE &&
- xmlStrEqual (paras->name, (const xmlChar *) "p") &&
- value && value[0]) {
- cur = xmlNodeGetLang (paras);
-
- tmp = strip_newlines ((const gchar *) value);
-
- if (!started) {
- started = TRUE;
- if (!cur) {
- best = xmlCharStrdup ("C");
- }
- else {
- best = xmlStrdup (cur);
- }
- best_value = g_strdup (tmp);
- }
- else {
- guint i;
-
- if (!cur || xmlStrEqual (cur, (const xmlChar *) "C")) {
- break;
- }
- /* See if the current lanaguage occurs
- * earlier than the previous best. */
- for (i = 0; langs[i] != NULL; ++i) {
- if (xmlStrEqual ((const xmlChar *) langs[i],
- best)) {
- break;
- }
- else if (xmlStrEqual ((const xmlChar *) langs[i],
- cur)) {
- xmlFree (best);
- best = xmlStrdup (cur);
- g_free (best_value);
- best_value = g_strdup (tmp);
- /* If this is the first
- * language on the
- * list of choices,
- * stop. We are not
- * going to go any
- * better. */
- if (i == 0) {
- break;
- }
- }
- }
- }
- g_free (tmp);
- xmlFree (cur);
- xmlFree (best);
- }
-
- paras = paras->next;
- xmlFree (value);
- }
- list = g_slist_prepend (list, best_value);
- started = FALSE;
- }
-
- list = g_slist_reverse (list);
-
- introduction_messages = g_new (char *, g_slist_length (list) + 1);
-
- for (i = 0, l = list; l; l = l->next, i++)
- introduction_messages[i] = l->data;
-
- introduction_messages[i] = NULL;
-
- g_slist_free (list);
-}
-
-static char*
-create_date_string (const char *value)
-{
- char *result;
- GDate *date;
- int day;
- int month;
- int year;
-
- /* YYYY-MM-DD */
- if (sscanf (value, "%d-%d-%d", &year, &month, &day) < 3)
- return NULL;
-
- date = g_date_new ();
-
- g_date_set_dmy (date, day, month, year);
-
- result = g_new0 (char, 24);
- g_date_strftime (result, 24, "%x", date);
-
- g_date_free (date);
-
- return result;
-}
-
-static gboolean
-get_version_info (char **version_string,
- char **distributor_string,
- char **build_date_string)
-{
- gchar *file;
-
- xmlDocPtr about;
- xmlNodePtr node;
- xmlNodePtr bits;
-
- char *platform = NULL;
- char *minor = NULL;
- char *micro = NULL;
-
- file = gnome_program_locate_file (NULL,
- GNOME_FILE_DOMAIN_APP_DATADIR,
- "gnome-version.xml",
- TRUE, NULL);
- if (!file)
- return FALSE;
-
- about = xmlParseFile (file);
- g_free (file);
-
- if (!about)
- return FALSE;
-
- node = about->children;
-
- if (g_ascii_strcasecmp ((const char *) node->name, "gnome-version")) {
- xmlFreeDoc (about);
- return FALSE;
- }
-
- bits = node->children;
-
- while (bits) {
- char *name = (char *)bits->name;
- char *value;
-
- if (!g_ascii_strcasecmp (name, "description"))
- get_description_messages (bits);
-
- value = (char *)xmlNodeGetContent (bits);
-
- if (!g_ascii_strcasecmp (name, "platform")
- && value && value[0])
- platform = g_strdup (value);
- else if (!g_ascii_strcasecmp (name, "minor") && value && value[0])
- minor = g_strdup (value);
- else if (!g_ascii_strcasecmp (name, "micro") && value && value[0])
- micro = g_strdup (value);
- else if (!g_ascii_strcasecmp (name, "distributor") && value && value[0])
- *distributor_string = g_strdup (value);
- else if (!g_ascii_strcasecmp (name, "date") && value && value[0])
- *build_date_string = create_date_string (value);
-
- bits = bits->next;
- xmlFree (value);
- }
-
- xmlFreeDoc (about);
-
- if (!minor)
- *version_string = g_strdup (platform);
-
- if (!*version_string && !micro)
- *version_string = g_strconcat (platform, ".", minor, NULL);
-
- if (!*version_string)
- *version_string = g_strconcat (platform, ".", minor, ".",
- micro, NULL);
-
- g_free (platform);
- g_free (minor);
- g_free (micro);
-
- return TRUE;
-}
-
-static gboolean
-display_version_info_on_term (void)
-{
- char *version_string = NULL;
- char *distributor_string = NULL;
- char *build_date_string = NULL;
-
- if (!get_version_info (&version_string,
- &distributor_string,
- &build_date_string)) {
- g_printerr (_("Could not get information about GNOME version."));
- return FALSE;
- }
-
- g_print (_("%s: %s\n"), _("Version"), version_string);
- g_print (_("%s: %s\n"), _("Distributor"), distributor_string);
- g_print (_("%s: %s\n"), _("Build Date"), build_date_string);
-
- g_free (version_string);
- g_free (distributor_string);
- g_free (build_date_string);
-
- return TRUE;
-}
-
-static void
-display_version_info (GnomeCanvasGroup *group)
-{
- char *version_string = NULL;
- char *distributor_string = NULL;
- char *build_date_string = NULL;
- char *format = NULL;
- char *text = NULL;
-
- GnomeCanvasItem *info;
- gdouble height = 0.0;
-
- if (!get_version_info (&version_string,
- &distributor_string,
- &build_date_string))
- show_error_dialog (_("Could not get information about GNOME version."));
-
- info = gnome_canvas_item_new (group,
- gnome_canvas_group_get_type (),
- "x", 10.0,
- NULL);
-
- format = g_strdup_printf ("<b>%s</b>%%s", _("%s: "));
-
- if (version_string && version_string[0]) {
- gdouble tmp;
- GnomeCanvasItem *item;
-
- text = g_strdup_printf (format,
- _("Version"), version_string);
- item = gnome_canvas_item_new (GNOME_CANVAS_GROUP (info),
- gnome_canvas_text_get_type (),
- "markup", text,
- "anchor", GTK_ANCHOR_NW,
- "x", 0.0,
- "y", height,
- NULL);
- g_free (text);
-
- g_object_get (item, "text_height", &tmp, NULL);
- height += tmp + 4.0;
- }
-
- if (distributor_string && distributor_string[0]) {
- gdouble tmp;
- GnomeCanvasItem *item;
-
- text = g_strdup_printf (format,
- _("Distributor"), distributor_string);
- item = gnome_canvas_item_new (GNOME_CANVAS_GROUP (info),
- gnome_canvas_text_get_type (),
- "markup", text,
- "anchor", GTK_ANCHOR_NW,
- "x", 0.0,
- "y", height,
- NULL);
- g_free (text);
-
- g_object_get (item, "text_height", &tmp, NULL);
- height += tmp + 4.0;
- }
-
- if (build_date_string && build_date_string[0]) {
- gdouble tmp;
- GnomeCanvasItem *item;
-
- text = g_strdup_printf (format,
- _("Build Date"), build_date_string);
- item = gnome_canvas_item_new (GNOME_CANVAS_GROUP (info),
- gnome_canvas_text_get_type (),
- "markup", text,
- "anchor", GTK_ANCHOR_NW,
- "x", 0.0,
- "y", height,
- NULL);
- g_free (text);
-
- g_object_get (item, "text_height", &tmp, NULL);
- height += tmp + 4.0;
- }
-
- g_free (format);
- g_free (version_string);
- g_free (distributor_string);
- g_free (build_date_string);
-
- gnome_canvas_item_set (info, "y", canvas_height - height, NULL);
- version_info_height = height;
-}
-
-static GtkWidget *
-create_canvas (void)
-{
- GdkColor color = {0, 0xffff, 0xffff, 0xffff};
- GtkWidget *canvas;
-
- HRefItem *href;
- gchar *text;
-
- GnomeCanvasItem *item;
- GnomeCanvasGroup *root;
- GnomeCanvasPoints *points;
-
- GdkPixbuf *header;
- GdkPixbuf *logo;
-
- gdouble current_x;
- gdouble current_y;
- gdouble dot_delta;
- gdouble tmp;
-
- /* set up a canvas */
- canvas = gnome_canvas_new ();
-
- gnome_canvas_set_scroll_region (GNOME_CANVAS (canvas), 0, 0,
- canvas_width, canvas_height);
- gtk_widget_set_size_request (canvas, canvas_width, canvas_height);
-
- gdk_colormap_alloc_color (gtk_widget_get_colormap (GTK_WIDGET (canvas)),
- &color, TRUE, TRUE);
-
- /* euhm? */
- gtk_widget_modify_bg (GTK_WIDGET (canvas), GTK_STATE_NORMAL, &color);
-
- root = GNOME_CANVAS_GROUP (GNOME_CANVAS (canvas)->root);
-
- /* the header */
- header = load_random_header ();
- if (!header)
- /* emergency stop complete with leaks */
- return NULL;
-
- item = gnome_canvas_item_new (root,
- gnome_canvas_pixbuf_get_type (),
- "x", 0.0,
- "y", 0.0,
- "pixbuf", header,
- NULL);
-
- /* load logo in advance, we need it's size */
- logo = load_logo ();
- if (!logo)
- /* emergency stop complete with leaks */
- return NULL;
-
- /* and a coulple o' links */
- current_x = 10.0 + (gdouble)gdk_pixbuf_get_width (logo) + 10.0;
- current_y = (gdouble)gdk_pixbuf_get_height (header) + 5.0;
-
- href = href_item_new (root,
- _("About GNOME"),
- "http://www.gnome.org/about/",
- &current_x, &current_y);
-
- /* make a nice guess for the dot delta */
- g_object_get (href->item, "text_height", &tmp, NULL);
- dot_delta = tmp / 4.5;
-
- /* draw a dot */
- item = create_dot (root, &current_x, &current_y, dot_delta);
-
- /* and more items on a likewise way.
- */
- href = href_item_new (root,
- _("News"),
- "http://news.gnome.org",
- &current_x, &current_y);
- item = create_dot (root, &current_x, &current_y, dot_delta);
-
- /*
- * FIXME: this used to be 'users' and it would be great to make it
- * users again once there is a user-centric page on the we site.
- */
- href = href_item_new (root,
- _("Software"),
- "http://www.gnome.org/softwaremap",
- &current_x, &current_y);
- item = create_dot (root, &current_x, &current_y, dot_delta);
-
- href = href_item_new (root,
- _("Developers"),
- "http://developer.gnome.org/",
- &current_x, &current_y);
- item = create_dot (root, &current_x, &current_y, dot_delta);
-
- href = href_item_new (root,
- _("Friends of GNOME"),
- "http://www.gnome.org/friends/",
- &current_x, &current_y);
- item = create_dot (root, &current_x, &current_y, dot_delta);
-
- href = href_item_new (root,
- _("Contact"),
- "http://www.gnome.org/contact/",
- &current_x, &current_y);
-
- /* resize */
- canvas_width = current_x;
- gnome_canvas_set_scroll_region (GNOME_CANVAS (canvas), 0, 0,
- canvas_width, canvas_height);
- gtk_widget_set_size_request (GTK_WIDGET (canvas),
- canvas_width, canvas_height);
-
- /* and a nice black stripe */
- points = gnome_canvas_points_new (2);
- points->coords[0] = 0.0;
- points->coords[1] = gdk_pixbuf_get_height (header);
- points->coords[2] = current_x;
- points->coords[3] = gdk_pixbuf_get_height (header);
-
- item = gnome_canvas_item_new (root,
- gnome_canvas_line_get_type (),
- "points", points,
- "fill_color", "#666666",
- "width_pixels", 1,
- NULL);
-
- gnome_canvas_points_free (points);
-
- /* the gnome logo */
- item = gnome_canvas_item_new (root,
- gnome_canvas_pixbuf_get_type (),
- "x", 10.0,
- "y", 10.0,
- "pixbuf", logo,
- NULL);
-
- /* and some introduction text */
- text = g_strdup_printf ("<big><big><b>%s</b></big></big>",
- _("Welcome to the GNOME Desktop"));
- item = gnome_canvas_item_new (root,
- gnome_canvas_text_get_type (),
- "markup", text,
- "anchor", GTK_ANCHOR_NW,
- "y", current_y + 25.0,
- "fill_color", "#000000",
- NULL);
- g_free (text);
-
- g_object_get (item, "text_width", &tmp, NULL);
- gnome_canvas_item_set (item,
- "x", (canvas_width - tmp) / 2.0,
- NULL);
-
-
- text = g_strdup_printf ("<big><b>%s</b></big>",
- _("Brought to you by:"));
- item = gnome_canvas_item_new (root,
- gnome_canvas_text_get_type (),
- "markup", text,
- "anchor", GTK_ANCHOR_NW,
- "y", current_y + 55.0,
- NULL);
- subheader = item;
- gnome_canvas_item_hide (item);
- g_free (text);
-
- g_object_get (item, "text_width", &tmp, NULL);
- gnome_canvas_item_set (item,
- "x", (canvas_width - tmp) / 2.0,
- NULL);
-
- /* and the version info */
- display_version_info (root);
-
- /* pfff done */
- return canvas;
-}
-
-/* the dialog */
-static gboolean
-quit_callback (GtkWidget *widget,
- gpointer user_data)
-{
- gtk_main_quit ();
-
- return FALSE;
-}
-
-static void
-response_callback (GtkDialog *dialog,
- int reponse_id,
- gpointer user_data)
-{
- if (reponse_id == GTK_RESPONSE_CLOSE)
- quit_callback (GTK_WIDGET (dialog), NULL);
-}
-
-static GtkWidget *
-create_about_dialog (void)
-{
- GtkWidget *dialog;
- GtkWidget *canvas;
-
- dialog = gtk_dialog_new_with_buttons (_("About the GNOME Desktop"),
- NULL, 0,
- GTK_STOCK_CLOSE,
- GTK_RESPONSE_CLOSE,
- NULL);
- gtk_dialog_set_default_response (GTK_DIALOG (dialog),
- GTK_RESPONSE_CLOSE);
-
- g_signal_connect (dialog, "delete_event",
- G_CALLBACK (quit_callback), NULL);
- g_signal_connect (dialog, "response",
- G_CALLBACK (response_callback), NULL);
-
- gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
- g_object_set (dialog,
- "allow_shrink", FALSE,
- "allow_grow", FALSE,
- NULL);
-
- canvas = create_canvas ();
- if (!canvas) {
- gtk_widget_destroy (dialog);
- return NULL;
- }
-
- /* start animations once the canvas has been mapped */
- g_signal_connect (canvas, "map",
- G_CALLBACK (start_animations), NULL);
-
- gtk_container_set_border_width
- (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), GNOME_PAD_SMALL);
- gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
- canvas, TRUE, TRUE, 0);
-
- return dialog;
-}
-
-static gboolean gnome_version = FALSE;
-
-static const GOptionEntry options[] = {
- { "gnome-version", 0, 0, G_OPTION_ARG_NONE, &gnome_version, N_("Display information on this GNOME version"), NULL },
- { NULL }
-};
-
-/* main */
-int
-main (int argc, char **argv)
-{
- GOptionContext *context;
- GnomeProgram *program;
- GtkWidget *dialog;
-
- bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
- bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
- textdomain (GETTEXT_PACKAGE);
-
- context = g_option_context_new (NULL);
- g_option_context_add_main_entries (context, options, GETTEXT_PACKAGE);
-
- program = gnome_program_init ("gnome-about", VERSION,
- LIBGNOMEUI_MODULE,
- argc, argv,
- GNOME_PARAM_APP_DATADIR, DATADIR,
- GNOME_PARAM_GOPTION_CONTEXT, context,
- NULL);
-
- if (gnome_version) {
- g_object_unref (program);
- return (display_version_info_on_term ()) ? 0 : 1;
- }
-
- gtk_window_set_default_icon_from_file (GNOME_ICONDIR
- "/gnome-logo-icon-transparent.png", NULL);
-
- dialog = create_about_dialog ();
- if (!dialog)
- return -1;
-
- gtk_widget_show_all (dialog);
-
- contributors_init ();
-
- gtk_main ();
-
- contributors_free ();
- g_object_unref (program);
-
- return 0;
-}
diff --git a/gnome-about/gnome-about.in b/gnome-about/gnome-about.in
new file mode 100644
index 00000000..6acecea2
--- /dev/null
+++ b/gnome-about/gnome-about.in
@@ -0,0 +1,1007 @@
+#!@PYTHON@
+# coding=utf-8
+
+'''
+gnome-about
+
+ # Pretty About Dialog for the GNOME Desktop #
+
+Copyright (C) 2007 Guillaume Seguin <guillaume@segu.in>
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+
+Authors:
+ Guillaume Seguin <guillaume@segu.in>
+ Vincent Untz <vuntz@gnome.org> (get_language_names () helper function)
+'''
+
+import pygtk
+pygtk.require ('2.0')
+
+import gobject
+from gobject.option import OptionGroup, OptionParser, make_option
+import gtk
+
+import gnome
+import cairo
+from math import pi
+
+import os, sys, random, time, gettext
+
+import xml.dom.minidom
+
+PACKAGE = "@PACKAGE_NAME@"
+VERSION = "@PACKAGE_VERSION@"
+GETTEXT_PACKAGE = "@GETTEXT_PACKAGE@"
+
+LOCALEDIR = "@LOCALEDIR@"
+DATADIR = "@DATADIR@"
+ICONDIR = "@ICONDIR@"
+
+LOGO_FILE = "gnome-64.png"
+
+gettext.install (GETTEXT_PACKAGE, LOCALEDIR, unicode = True)
+
+header_links = [
+ (_("About GNOME"), "http://www.gnome.org/about/"),
+ (_("News"), "http://news.gnome.org/"),
+ (_("GNOME Library"), "http://library.gnome.org/"),
+ (_("Friends of GNOME"), "http://www.gnome.org/friends/"),
+ (_("Contact"), "http://www.gnome.org/contact/"),
+]
+
+translated_contributors = [
+ _("The Mysterious GEGL"),
+ _("The Squeaky Rubber GNOME"),
+ _("Wanda The GNOME Fish")
+]
+
+default_link_color = gtk.gdk.Color (0, 0, 65535)
+
+def locate_file (program, file):
+ '''Wrap gnome_program_locate_file to avoid ugly duplication'''
+ file = program.locate_file (gnome.FILE_DOMAIN_APP_DATADIR, file, True)
+ if not file:
+ return False
+ return file[0]
+
+def cleanup_date (date):
+ '''Parse a date as found in gnome-version.xml and nicely format it'''
+ try:
+ return time.strftime ("%x", time.strptime (date, "%Y-%m-%d"))
+ except:
+ return False
+
+# Imported from GNOME's Sabayon
+# (sabayon/admin-tool/lockdown/disabledapplets.py)
+# There's no wrapper for g_get_language_names (). Ugly workaround:
+# Note that we don't handle locale alias...
+def get_language_names ():
+ if "LANGUAGE" in os.environ.keys () and os.environ["LANGUAGE"] != "":
+ env_lang = os.environ["LANGUAGE"].split ()
+ elif "LC_ALL" in os.environ.keys () and os.environ["LC_ALL"] != "":
+ env_lang = os.environ["LC_ALL"].split ()
+ elif "LC_MESSAGES" in os.environ.keys () and os.environ["LC_MESSAGES"] != "":
+ env_lang = os.environ["LC_MESSAGES"].split ()
+ elif "LANG" in os.environ.keys () and os.environ["LANG"] != "":
+ env_lang = os.environ["LANG"].split ()
+ else:
+ env_lang = []
+
+ env_lang.reverse ()
+ languages = []
+
+ for language in env_lang:
+ start_pos = 0
+ mask = 0
+ uscore_pos = language.find ("_")
+ if uscore_pos != -1:
+ start_pos = uscore_pos
+ mask += 1 << 2
+ dot_pos = language.find (".", start_pos)
+ if dot_pos != -1:
+ start_pos = dot_pos
+ mask += 1 << 0
+ at_pos = language.find ("@", start_pos)
+ if at_pos != -1:
+ start_pos = at_pos
+ mask += 1 << 1
+
+ if uscore_pos != -1:
+ lang = language[:uscore_pos]
+ elif dot_pos != -1:
+ lang = language[:dot_pos]
+ elif at_pos != -1:
+ lang = language[:at_pos]
+ else:
+ lang = language
+
+ if uscore_pos != -1:
+ if dot_pos != -1:
+ territory = language[uscore_pos:dot_pos]
+ elif at_pos != -1:
+ territory = language[uscore_pos:at_pos]
+ else:
+ territory = language[uscore_pos:]
+ else:
+ territory = ""
+
+ if dot_pos != -1:
+ if at_pos != -1:
+ codeset = language[dot_pos:at_pos]
+ else:
+ codeset = language[dot_pos:]
+ else:
+ codeset = ""
+
+ if at_pos != -1:
+ modifier = language[at_pos:]
+ else:
+ modifier = ""
+
+ for i in range (mask + 1):
+ if i & ~mask == 0:
+ newlang = lang
+ if (i & 1 << 2):
+ newlang += territory
+ if (i & 1 << 0):
+ newlang += codeset
+ if (i & 1 << 1):
+ newlang += modifier
+ languages.insert (0, newlang)
+
+ return languages
+
+class GettableList (list):
+ '''Dumb wrapper around Python list with a get () method to iterate \
+the list'''
+
+ current = 0
+
+ def get (self):
+ if not len (self):
+ return None
+ if self.current == -1:
+ item = None
+ else:
+ item = self[self.current]
+ self.current += 1
+ if self.current == len (self):
+ self.current = -1
+ else:
+ self.current = self.current % len (self)
+ return item
+
+class GnomeContributors (GettableList):
+ '''Randomized contributors list'''
+
+ program = None
+ current = 0
+
+ def __init__ (self, program):
+ '''Initiate object and load contributors lists'''
+ super (GnomeContributors, self).__init__ ()
+ self.program = program
+ map (self.append, translated_contributors)
+ self.load_from_file ("contributors.list")
+ self.load_from_file ("foundation-members.list")
+ random.shuffle (self) # Randomize list...
+
+ def load_from_file (self, file):
+ '''Load a list of contributors and validate it'''
+ def validate_contributor (contrib):
+ try:
+ contrib.encode ("utf8")
+ return len (contrib) > 0 and contrib[0] != "#"
+ except Exception, e:
+ print e
+ return False
+
+ path = locate_file (self.program, file)
+
+ if not path:
+ print '''Warning: "%s" file not found.''' % file
+ return
+
+ f = open (path, "r")
+ try:
+ data = f.readlines ()
+ finally:
+ f.close ()
+
+ '''Cleanup list'''
+ data = map (lambda s: s.rstrip (), data)
+
+ '''Check that the file begins with the correct header'''
+ if not data or data[0] != "# gnome-about contributors - format 1":
+ return
+
+ '''Filter the contributors list and append it'''
+ contributors = filter (validate_contributor, data)
+ map (self.append, contributors)
+
+ def get (self):
+ '''Return a contributor from the currently randomized list. \
+ If we hit the end of the list, randomize it again'''
+ contributors_count = len (self)
+ if not contributors_count:
+ print "Warning: empty contributors list."
+ return
+ contributor = self[self.current]
+ self.current += 1
+ if self.current >= contributors_count:
+ '''Remove the last item of the list and reinsert it after \
+ shuffling to make sure it won't get displayed twice in a row'''
+ self.pop ()
+ random.shuffle (self)
+ index = random.randint (contributors_count / 2,
+ contributors_count)
+ self.insert (index, contributor)
+ self.current = 0
+ return contributor
+
+# Animation is done using:
+# * A custom gtk.Label, for catching mouse press events
+# * A gtk.Alignment, for positionning and scrolling (the actual animation)
+# * A gtk.Layout, so that the Alignment can be wider than what's displayed
+# and thus let the Label appear and disappear smoothly
+
+class AnimatedLabel (gtk.Layout):
+ '''Pretty animated label'''
+
+ items = None # items must either be a GettableList object
+ # or expose a get () method'''
+ timeout = 0
+ format = "" # format must be a valid formatting string for a single %s
+
+ item = None
+ next = None
+
+ current = None
+ label = None
+ source = None
+ state = 0 # 0 = appearing ; 1 = landed ; 2 = vanishing
+ pos = 0.0
+
+ width = 0
+ height = 0
+
+ def __init__ (self, items, width, height, timeout, format = "%s"):
+ '''Initiate object'''
+ super (AnimatedLabel, self).__init__ ()
+ self.items = items
+ self.next = self.items.get () # Pop the first item
+ self.width = width
+ self.height = height
+ self.timeout = timeout
+ self.format = format
+ self.set_size_request (width, height)
+ self.connect ("button-press-event", self.on_button_press)
+ self.connect ("map", self.reset_animation)
+
+ def reset_animation (self, *args):
+ '''Reset label and fire animation timer'''
+ self.reset_label ()
+ if not self.label:
+ return
+ self.source = gobject.timeout_add (5, self.animate)
+
+ def make_label (self):
+ '''Build the label widgets'''
+ self.label = WindowedLabel ()
+ self.label.connect ("button-press-event", self.on_button_press)
+ self.label.set_justify (gtk.JUSTIFY_FILL)
+ self.label.set_line_wrap (True)
+ self.label.set_markup (self.format % self.item)
+ self.label.set_selectable (True)
+
+ def reset_label (self):
+ '''Drop current label if any and create the new one'''
+ if self.current:
+ self.remove (self.current)
+ self.current = None
+ self.label = None
+ self.item = self.next
+ self.next = self.items.get ()
+ if not self.item:
+ return False
+ self.make_label ()
+ self.state = -1
+
+ def on_button_press (self, widget, event):
+ '''Switch to next item upon left click'''
+ if event.button != 1 or not self.current:
+ return
+ # Remove the current timeout if any to avoid bad side effects
+ if self.source:
+ gobject.source_remove (self.source)
+ self.animate ()
+ return True
+
+class VertAnimatedLabel (AnimatedLabel):
+ '''Vertically animated label'''
+
+ rewind_text = ""
+ last_label_height = 0
+
+ def rewind_animate (self):
+ '''Animation function for the rewind step'''
+ self.source = None
+ if self.state == -2:
+ self.item = self.rewind_text
+ self.make_label ()
+ label_height = self.label.size_request ()[1]
+ total_height = self.height + label_height
+ self.pos = float (self.last_label_height) / total_height
+ self.current.set (0.5, self.pos, 0, 0)
+ self.state = 0
+ self.source = gobject.timeout_add (10, self.rewind_animate)
+ elif self.state == 0:
+ if self.pos < 1.0:
+ '''Move towards the bottom position'''
+ self.pos = min (1.0, self.pos + 0.01)
+ self.current.set (0.5, self.pos, 0, 0)
+ self.source = gobject.timeout_add (10, self.rewind_animate)
+ else:
+ '''Bottommost position reached'''
+ self.rewind_text = ""
+ self.reset_animation ()
+ return False
+
+ def animate (self):
+ '''The actual animation function'''
+ self.source = None
+ if self.state == -2:
+ self.rewind_animate ()
+ elif self.state == -1:
+ self.rewind_text += "\n\n%s" % self.item
+ self.state = 0
+ self.animate ()
+ elif self.state == 0:
+ if self.pos:
+ '''Move towards the top position'''
+ self.pos = max (0, self.pos - 0.02)
+ label_height = self.label.size_request ()[1]
+ total_height = self.height + label_height
+ real_pos = float (self.pos * self.height + label_height) \
+ / total_height
+ self.current.set (0.5, real_pos, 0, 0)
+ self.source = gobject.timeout_add (5, self.animate)
+ else:
+ '''Topmost position reached'''
+ self.state = 1
+ self.pos = 1.0
+ self.source = gobject.timeout_add (self.timeout, self.animate)
+ elif self.state == 1:
+ '''Dont let selected labels vanish until they are unselected'''
+ if self.label.get_selection_bounds () == ():
+ self.state = 2
+ self.source = gobject.timeout_add (5, self.animate)
+ elif self.state == 2:
+ if not self.next:
+ self.state = -2
+ self.last_label_height = self.label.size_request ()[1]
+ self.reset_animation ()
+ self.source = gobject.timeout_add (1, self.animate)
+ elif self.pos:
+ '''Move out of the visible region of the Layout'''
+ self.pos = max (0, self.pos - 0.02)
+ label_height = self.label.size_request ()[1]
+ total_height = self.height + label_height
+ real_pos = float (self.pos * label_height) \
+ / total_height
+ self.current.set (0.5, real_pos, 0, 0)
+ self.source = gobject.timeout_add (5, self.animate)
+ else:
+ '''Label has disappeared, bye bye'''
+ self.reset_animation ()
+ return False
+
+ def make_label (self):
+ '''Build a new label widget'''
+ super (VertAnimatedLabel, self).make_label ()
+ if not self.label:
+ return
+ self.label.set_size_request (self.width, -1)
+ self.current = gtk.Alignment (0.0, 1.0)
+ label_height = self.label.size_request ()[1]
+ height = self.size_request ()[1]
+ self.current.set_size_request (-1, 2 * label_height + height)
+ self.current.add (self.label)
+ self.put (self.current, 0, - label_height)
+ self.pos = 1.0
+ self.show_all ()
+
+class HorzAnimatedLabel (AnimatedLabel):
+ '''Horizontally animated label'''
+
+ def animate (self):
+ '''The actual animation function'''
+ self.source = None
+ if self.state == -2:
+ self.reset_animation ()
+ elif self.state <= 0:
+ if self.pos != 0.5:
+ '''Move towards the center position'''
+ self.pos = max (0.5, self.pos - 0.02)
+ self.current.set (self.pos, 0.5, 0, 0)
+ self.source = gobject.timeout_add (5, self.animate)
+ else:
+ '''Center position reached, switch to return mode'''
+ self.state = 1
+ self.source = gobject.timeout_add (self.timeout, self.animate)
+ elif self.state == 1:
+ '''Dont let selected labels vanish until they are unselected'''
+ if self.label.get_selection_bounds () == ():
+ self.state = 2
+ self.source = gobject.timeout_add (5, self.animate)
+ elif self.state == 2:
+ if self.pos:
+ '''Disappear by moving left'''
+ self.pos = max (0, self.pos - 0.02)
+ self.current.set (self.pos, 0.5, 0, 0)
+ self.source = gobject.timeout_add (5, self.animate)
+ else:
+ '''Left position reached, let's move on'''
+ self.reset_animation ()
+ return False
+
+ def make_label (self):
+ '''Build a new label widget'''
+ super (HorzAnimatedLabel, self).make_label ()
+ if not self.label:
+ return
+ self.label.set_size_request (-1, self.height)
+ self.current = gtk.Alignment (1.0, 0.0)
+ label_width = self.label.size_request ()[0]
+ width = self.size_request ()[0]
+ self.current.set_size_request (2 * label_width + width, -1)
+ self.current.add (self.label)
+ self.put (self.current, - label_width, 0)
+ self.pos = 1.0
+ self.show_all ()
+
+class WindowedLabel (gtk.Label):
+ '''Custom gtk.Label with an overlapping input-only gtk.gdk.Window'''
+
+ event_window = None
+
+ def __init__ (self, debug = False):
+ '''Initialize object and plug all signals'''
+ self.debug = debug
+ super (WindowedLabel, self).__init__ ()
+
+ def do_realize (self):
+ '''Create a custom GDK window with which we will be able to play'''
+ gtk.Label.do_realize (self)
+ event_mask = self.get_events () | gtk.gdk.BUTTON_PRESS_MASK \
+ | gtk.gdk.BUTTON_RELEASE_MASK \
+ | gtk.gdk.KEY_PRESS_MASK
+ self.event_window = gtk.gdk.Window (parent = self.get_parent_window (),
+ window_type = gtk.gdk.WINDOW_CHILD,
+ wclass = gtk.gdk.INPUT_ONLY,
+ event_mask = event_mask,
+ x = self.allocation.x,
+ y = self.allocation.y,
+ width = self.allocation.width,
+ height = self.allocation.height)
+ self.event_window.set_user_data (self)
+
+ def do_unrealize (self):
+ '''Destroy event window on unrealize'''
+ self.event_window.set_user_data (None)
+ self.event_window.destroy ()
+ gtk.Label.do_unrealize (self)
+
+ def do_size_allocate (self, allocation):
+ '''Move & resize the event window to fit the Label's one'''
+ gtk.Label.do_size_allocate (self, allocation)
+ if self.flags () & gtk.REALIZED:
+ self.event_window.move_resize (allocation.x, allocation.y,
+ allocation.width, allocation.height)
+
+ def do_map (self):
+ '''Show event window'''
+ gtk.Label.do_map (self)
+ self.event_window.show ()
+ '''Raise the event window to make sure it is over the Label's one'''
+ self.event_window.raise_ ()
+
+ def do_unmap (self):
+ '''Hide event window on unmap'''
+ self.event_window.hide ()
+ gtk.Label.do_unmap (self)
+
+gobject.type_register (WindowedLabel)
+
+class HyperLink (WindowedLabel):
+ '''Clickable www link label'''
+
+ url = ""
+ menu = None
+ selection = None
+
+ def __init__ (self, label, url):
+ '''Initialize object'''
+ super (HyperLink, self).__init__ ()
+ markup = "<b><u>%s</u></b>" % label
+ self.set_markup (markup)
+ self.set_selectable (True)
+ self.url = url
+ self.create_menu ()
+ link_color = self.style_get_property ("link-color")
+ if not link_color:
+ link_color = default_link_color
+ self.modify_fg (gtk.STATE_NORMAL, link_color)
+
+ def open_url (self, *args):
+ '''Use GNOME API to open the url'''
+ try:
+ gnome.url_show (self.url)
+ except Exception, e:
+ print '''Warning: could not open "%s": %s''' % self.url, e
+
+ def copy_url (self, *args):
+ '''Copy URL to Clipboard'''
+ clipboard = gtk.clipboard_get ("CLIPBOARD")
+ clipboard.set_text (self.url)
+
+ def create_menu (self):
+ '''Create the popup menu that will be displayed upon right click'''
+ self.menu = gtk.Menu ()
+ open_item = gtk.ImageMenuItem (_("_Open URL"))
+ open_image = gtk.image_new_from_stock (gtk.STOCK_OPEN,
+ gtk.ICON_SIZE_MENU)
+ open_item.set_image (open_image)
+ open_item.connect ("activate", self.open_url)
+ open_item.show ()
+ self.menu.append (open_item)
+ copy_item = gtk.ImageMenuItem (_("_Copy URL"))
+ copy_image = gtk.image_new_from_stock (gtk.STOCK_COPY,
+ gtk.ICON_SIZE_MENU)
+ copy_item.set_image (copy_image)
+ copy_item.connect ("activate", self.copy_url)
+ copy_item.show ()
+ self.menu.append (copy_item)
+
+ def display_menu (self, button, time, place = False):
+ '''Display utility popup menu'''
+ if place:
+ alloc = self.get_allocation ()
+ pos = self.event_window.get_origin ()
+ x = pos[0]
+ y = pos[1] + alloc.height
+ func = lambda *a: (x, y, True)
+ else:
+ func = None
+ self.menu.popup (None, None, func, button, time)
+
+ def do_map (self):
+ '''Select the HAND2 cursor on map'''
+ WindowedLabel.do_map (self)
+ cursor = gtk.gdk.Cursor (gtk.gdk.HAND2)
+ self.event_window.set_cursor (cursor)
+
+ def do_button_press_event (self, event):
+ '''Update selection bounds infos or display popup menu'''
+ if event.button == 1:
+ self.selection = self.get_selection_bounds ()
+ elif event.button == 3:
+ self.display_menu (event.button, event.time)
+ return True
+ WindowedLabel.do_button_press_event (self, event)
+
+ def do_button_release_event (self, event):
+ '''Open url if selection hasn't changed since initial press'''
+ if event.button == 1:
+ selection = self.get_selection_bounds ()
+ if selection == self.selection:
+ self.open_url ()
+ return True
+ WindowedLabel.do_button_release_event (self, event)
+
+ def do_key_press_event (self, event):
+ '''Open url when Return key is pressed'''
+ if event.keyval == gtk.keysyms.Return:
+ self.open_url ()
+ return True
+ elif event.keyval == gtk.keysyms.Menu \
+ or (event.keyval == gtk.keysyms.F10 \
+ and event.state & gtk.accelerator_get_default_mod_mask() == \
+ gtk.gdk.SHIFT_MASK):
+ self.display_menu (event.keyval, event.time, place = True)
+ return True
+ WindowedLabel.do_key_press_event (self, event)
+
+gobject.type_register (HyperLink)
+
+class GnomeLogo (gtk.Widget):
+
+ def __init__ (self, parent, file):
+ gtk.Widget.__init__ (self)
+
+ self._surface = cairo.ImageSurface.create_from_png (file)
+
+ text_color = parent.get_style ().text[gtk.STATE_NORMAL]
+
+ cr = cairo.Context (self._surface)
+ cr.set_source_rgb (text_color.red, text_color.green, text_color.blue)
+ cr.set_operator (cairo.OPERATOR_ATOP)
+ cr.paint ()
+
+ width = self._surface.get_width ()
+ height = self._surface.get_height ()
+ self.set_size_request (width, height)
+
+ self.set_flags(self.flags() | gtk.NO_WINDOW)
+
+ def do_expose_event (self, event):
+ cr = self.window.cairo_create ()
+
+ cr.set_operator (cairo.OPERATOR_OVER)
+ cr.set_source_surface (self._surface, 10, 10)
+ cr.paint ()
+
+gobject.type_register (GnomeLogo)
+
+class GnomeAboutHeader (gtk.Layout):
+ '''Pretty header for gnome-about'''
+
+ program = None
+ links = []
+
+ width = 0
+ height = 0
+
+ def __init__ (self, program, links):
+ '''Initialize object, plug map signal'''
+ super (GnomeAboutHeader, self).__init__ ()
+ self.program = program
+ self.links = links
+
+ def do_realize (self):
+ '''Load header and build links'''
+ gtk.Layout.do_realize (self)
+
+ current_x = 0
+ current_y = 0
+ base_y = 0
+
+ header = self.load_header ()
+ if header:
+ self.put (header, 0, 0)
+ current_y = header.get_pixbuf ().get_height ()
+ base_y = current_y + 4
+ line = self.create_line ()
+ image = gtk.Image ()
+ image.set_from_pixmap (line, None)
+ self.put (image, 0, current_y)
+
+ logo = self.load_logo ()
+ if logo:
+ self.put (logo, 0, 0)
+ logo_size = logo.get_size_request ()
+ current_x += logo_size[0] + 25
+ current_y = logo_size[1] + 20
+
+ dot = self.create_dot ()
+
+ def make_link_widget (link):
+ '''Helper function which makes an HyperLink and shows it'''
+ label = HyperLink (link[0], link[1])
+ label.show_all ()
+ return label
+
+ widgets = map (make_link_widget, self.links)
+ put_widgets = 0
+ for widget in widgets:
+ if put_widgets > 0:
+ if dot:
+ image = gtk.Image ()
+ image.set_from_pixmap (dot, None)
+ self.put (image, current_x + 5, base_y + 6)
+ current_x += 16
+ self.put (widget, current_x, base_y)
+ current_x += widget.size_request ()[0]
+ put_widgets += 1
+
+ self.width = current_x + 10
+ self.height = current_y
+ self.set_size_request (self.width, self.height)
+ self.show_all ()
+
+ def load_header (self):
+ '''Load a random header image as a gtk.Image'''
+
+ directory = locate_file (self.program, "headers")
+ if not directory:
+ print "Warning: header images directory not found."
+ return None
+
+ try:
+ headers = os.listdir (directory)
+ except:
+ print "Warning: failed to read header images directory."
+ return None
+
+ headers = filter (lambda s: s[-4:] in (".png", ".gif"), headers)
+ header = random.choice (headers)
+
+ file = os.path.join (directory, header)
+ try:
+ pixbuf = gtk.gdk.pixbuf_new_from_file (file)
+ except:
+ print '''Warning: failed to load header image "%s".''' % file
+ return None
+
+ image = gtk.Image ()
+ image.set_from_pixbuf (pixbuf)
+
+ return image
+
+ def load_logo (self):
+ '''Load a GNOME foot logo as a gtk.Image'''
+
+ file = locate_file (self.program, LOGO_FILE)
+ if not file:
+ print '''Warning: GNOME logo file "%s" not found.''' % LOGO_FILE
+ return None
+
+ try:
+ logo = GnomeLogo (self, file)
+ except Exception:
+ print '''Warning: failed to load GNOME logo image "%s".''' % file
+ return None
+
+ return logo
+
+ def create_dot (self):
+ '''Create a pixmap containing a simple dot'''
+ pixmap = gtk.gdk.Pixmap (self.window, 6, 6)
+ context = pixmap.cairo_create ()
+ context.set_operator (cairo.OPERATOR_SOURCE)
+ context.set_source_color (self.style.bg[self.state])
+ context.paint ()
+ context.set_operator (cairo.OPERATOR_OVER)
+ context.set_source_color (self.style.fg[self.state])
+ context.arc (3, 3, 2.3, 0, 2 * pi)
+ context.fill ()
+ return pixmap
+
+ def create_line (self, width = 2000, height = 1):
+ '''Create a pixmap containing a simple line'''
+ pixmap = gtk.gdk.Pixmap (self.window, width, height)
+ context = pixmap.cairo_create ()
+ context.set_operator (cairo.OPERATOR_SOURCE)
+ context.set_source_rgb (0, 0, 0)
+ context.paint ()
+ return pixmap
+
+gobject.type_register (GnomeAboutHeader)
+
+class GnomeAbout (gtk.Dialog):
+ '''Super pretty About Dialog for the GNOME Desktop'''
+
+ program = None
+ header = None
+ contributors = None
+ description_messages = GettableList ()
+ system_infos = []
+
+ def __init__ (self, ui = True):
+ '''Initialize underlying gnome.Program, Contributors list, UI...'''
+ super (GnomeAbout, self).__init__ (_("About the GNOME Desktop"),
+ buttons = (gtk.STOCK_CLOSE,
+ gtk.RESPONSE_CLOSE))
+
+ defs = {gnome.PARAM_APP_DATADIR : DATADIR}
+ self.program = gnome.program_init ("gnome-about", VERSION,
+ properties = defs)
+ # Immediately fetch system infos to load description messages
+ self.system_infos = self.get_system_infos ()
+
+ if not ui:
+ return
+
+ self.contributors = GnomeContributors (self.program)
+
+ icon_file = ICONDIR + "/gnome-logo-icon-transparent.png"
+ try:
+ self.set_icon_from_file (icon_file)
+ except gobject.GError:
+ pass
+
+ self.create_ui ()
+
+ self.set_default_response (gtk.RESPONSE_CLOSE)
+ self.set_position (gtk.WIN_POS_CENTER_ALWAYS)
+ map (lambda prop: self.set_property (prop[0], prop[1]),
+ [("allow-grow", False), ("allow-shrink", False)])
+ self.connect ("delete-event", gtk.main_quit)
+ self.connect ("response", self.response_callback)
+
+ def gnome_version (self):
+ '''Output basic GNOME version information to console'''
+ def print_info (info):
+ infos_dict = {"name": info[0], "value": info[1]}
+ # Translators: %(name)s and %(value)s should not be translated:
+ # it's a way to identify a string, so just handle them like %s
+ print _("%(name)s: %(value)s") % infos_dict
+ map (print_info, self.system_infos)
+
+ def create_ui (self):
+ '''Fill our Dialog with some lovely widgets'''
+ self.set_has_separator (False)
+ main_box = self.get_children ()[0] # Get the internal Dialog VBox
+
+ '''Pretty header'''
+ self.header = GnomeAboutHeader (self.program, header_links)
+ main_box.pack_start (self.header)
+
+ welcome_label = WindowedLabel ()
+ welcome_label.set_markup ("<big><big><b>%s</b></big></big>" % \
+ _("Welcome to the GNOME Desktop"))
+ main_box.pack_start (welcome_label)
+
+ descriptions_label = VertAnimatedLabel (self.description_messages,
+ 300, 120, 8000, "%s")
+ welcome_label.connect ("button-press-event",
+ descriptions_label.on_button_press)
+ box = gtk.EventBox ()
+ alignment = gtk.Alignment (0.5, 0.5)
+ alignment.set_padding (10, 10, 0, 0)
+ alignment.add (descriptions_label)
+ box.connect ("button-press-event", descriptions_label.on_button_press)
+ box.add (alignment)
+ main_box.pack_start (box)
+
+ by_label = WindowedLabel (True)
+ by_label.set_markup ("<big><b>%s</b></big>" % _("Brought to you by:"))
+ main_box.pack_start (by_label)
+
+ alignment = gtk.Alignment (0.5, 0.5)
+ '''Realize the header right now to get everything (especially the
+contributors list) correctly positionned and sized.'''
+ self.header.realize ()
+ width = self.header.width
+ label = HorzAnimatedLabel (self.contributors, width,
+ 30, 2500, "<b>%s</b>")
+ by_label.connect ("button-press-event", label.on_button_press)
+ label.show_all ()
+ alignment.add (label)
+
+ main_box.pack_start (alignment)
+
+ '''System info labels'''
+ def make_info_label (info):
+ if not info[1]:
+ return False
+ label = gtk.Label ()
+ infos_dict = {"name": info[0], "value": info[1]}
+ # Translators: %(name)s and %(value)s should not be translated:
+ # it's a way to identify a string, so just handle them like %s
+ label.set_markup (_("<b>%(name)s:</b> %(value)s") % infos_dict)
+ label.set_selectable (True)
+ label.connect ("focus-out-event",
+ lambda l, e: l.select_region (-1, -1))
+ alignment = gtk.Alignment (0, 0.5)
+ alignment.set_padding (0, 4, 8, 0)
+ alignment.add (label)
+ return alignment
+
+ info_labels = map (make_info_label, self.system_infos)
+ info_labels = filter (lambda l: l <> False, info_labels)
+ map (lambda l: main_box.pack_start (l, False, False), info_labels)
+
+ main_box.show_all ()
+
+ def get_system_infos (self):
+ '''Fetch various system infos'''
+ file = locate_file (self.program, "gnome-version.xml")
+ if not file:
+ print '''Warning: "gnome-version.xml" file not found.'''
+ return []
+
+ f = open (file, "r")
+ try:
+ document = xml.dom.minidom.parse (f)
+ finally:
+ f.close ()
+
+ if document.firstChild.nodeName != "gnome-version":
+ print '''Warning: corrupted "gnome-version.xml".'''
+ return []
+
+ infos = {
+ "platform" : "",
+ "minor" : "",
+ "micro" : "",
+ "distributor" : "",
+ "date" : ""
+ }
+
+ for node in document.firstChild.childNodes:
+ if node.nodeName in infos:
+ infos[node.nodeName] = node.firstChild.nodeValue
+ elif node.nodeName == "description":
+ self.load_description_messages (node)
+
+ '''Format version'''
+ if not len (infos["minor"]):
+ version = infos["platform"]
+ elif not len (infos["micro"]):
+ version = "%s.%s" % (infos["platform"], infos["minor"])
+ else:
+ version = "%s.%s.%s" % (infos["platform"], infos["minor"],
+ infos["micro"])
+
+ return [
+ (_("Version"), version),
+ (_("Distributor"), infos["distributor"]),
+ (_("Build Date"), cleanup_date (infos["date"]))
+ ]
+
+ def load_description_messages (self, node):
+ '''Find the best translation of each description message'''
+ languages = get_language_names () + [""]
+ def desc_filter_func (node):
+ '''Helper filter function for XML descriptions'''
+ return node.nodeName == "p" \
+ and node.getAttribute ("xml:lang") in languages
+ def desc_sort_func (a, b):
+ '''Helper sorting function to sort translated messages'''
+ return cmp (languages.index (a), languages.index (b))
+ descs = filter (desc_filter_func, node.childNodes)
+ raw_descs = filter (lambda n: n.getAttribute ("xml:lang") == "", descs)
+ i = -1
+ translations = []
+ for desc in raw_descs:
+ new_i = descs.index (desc)
+ if i != - 1:
+ translations.append (descs[i:new_i])
+ i = new_i
+ messages = GettableList ()
+ for block in translations:
+ sorted_descs = sorted (block, cmp = desc_sort_func,
+ key = lambda n: n.getAttribute ("xml:lang"))
+ best = sorted_descs[0].firstChild.nodeValue
+ messages.append (best)
+ self.description_messages = messages
+
+ def response_callback (self, widget, response):
+ '''Handle dialog response when Close button is triggered'''
+ if response == gtk.RESPONSE_CLOSE:
+ gtk.main_quit ()
+
+if __name__ == "__main__":
+ parser = OptionParser (
+ option_list = [
+ make_option ("--gnome-version",
+ action="store_true",
+ dest="gnome_version",
+ help=_("Display information on this GNOME version")),
+ ])
+ #FIXME: http://bugzilla.gnome.org/show_bug.cgi?id=496278
+ parser.parse_args (sys.argv)
+ if parser.values.gnome_version:
+ about = GnomeAbout (ui = False)
+ about.gnome_version ()
+ else:
+ about = GnomeAbout ()
+ about.show_all ()
+ try:
+ gtk.main ()
+ except KeyboardInterrupt:
+ pass