diff options
Diffstat (limited to 'shell/e-shell-about-box.c')
-rw-r--r-- | shell/e-shell-about-box.c | 372 |
1 files changed, 372 insertions, 0 deletions
diff --git a/shell/e-shell-about-box.c b/shell/e-shell-about-box.c new file mode 100644 index 0000000000..71390c5313 --- /dev/null +++ b/shell/e-shell-about-box.c @@ -0,0 +1,372 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* e-shell-about-box.c + * + * Copyright (C) 2001 Ximian, Inc. + * + * 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. + * + * Author: Ettore Perazzoli <ettore@ximian.com> + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "e-shell-about-box.h" + +#include <gal/util/e-util.h> + +#include <gtk/gtkeventbox.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + + +#define PARENT_TYPE gtk_event_box_get_type () +static GtkEventBoxClass *parent_class = NULL; + +static const char *text[] = { + "", + N_("Evolution " VERSION), + N_("Copyright 1999, 2000, 2001 Ximian, Inc."), + "", + N_("Brought to you by"), + "", + "Seth Alves", + "Anders Carlsson", + "Damon Chaplin", + "Clifford R. Conover", + "Anna Dirks", + "Miguel de Icaza", + "Radek Doulik", + "Arturo Espinoza", + "Larry Ewing", + "Nat Friedman", + "Bertrand Guiheneuf", + "Iain Holmes", + "Tuomas Kuosmanen", + "Christopher J. Lahey", + "Jason Leach", + "Matthew Loper", + "Federico Mena", + "Rodrigo Moya", + "Eskil Heyn Olsen", + "Jesse Pavel", + "Ettore Perazzoli", + "JP Rosevear", + "Jeffrey Stedfast", + "Jakub Steiner", + "Russell Steinthal", + "Peter Teichman", + "Chris Toshok", + "Jon Trowbridge", + "Peter Williams", + "Dan Winship", + "Michael Zucchi" +}; +#define NUM_TEXT_LINES (sizeof (text) / sizeof (*text)) + +struct _EShellAboutBoxPrivate { + GdkPixmap *pixmap; + GdkPixmap *text_background_pixmap; + GdkGC *clipped_gc; + int text_y_offset; + int timeout_id; +}; + + +#define ANIMATION_DELAY 40 + +#define WIDTH 400 +#define HEIGHT 200 + +#define TEXT_Y_OFFSET 57 +#define TEXT_X_OFFSET 60 +#define TEXT_WIDTH (WIDTH - 2 * TEXT_X_OFFSET) +#define TEXT_HEIGHT 90 + +#define IMAGE_PATH EVOLUTION_IMAGES "/about-box.png" + + +/* The callback. */ + +static int +timeout_callback (void *data) +{ + EShellAboutBox *about_box; + EShellAboutBoxPrivate *priv; + GdkRectangle redraw_rect; + GtkWidget *widget; + int line_height; + int first_line; + int y; + int i; + + about_box = E_SHELL_ABOUT_BOX (data); + priv = about_box->priv; + + widget = GTK_WIDGET (about_box); + + line_height = widget->style->font->ascent + widget->style->font->descent; + + if (priv->text_y_offset < TEXT_HEIGHT) { + y = TEXT_Y_OFFSET + (TEXT_HEIGHT - priv->text_y_offset); + first_line = 0; + } else { + y = TEXT_Y_OFFSET - ((priv->text_y_offset - TEXT_HEIGHT) % line_height); + first_line = (priv->text_y_offset - TEXT_HEIGHT) / line_height; + } + + gdk_draw_pixmap (priv->pixmap, priv->clipped_gc, priv->text_background_pixmap, + 0, 0, + TEXT_X_OFFSET, TEXT_Y_OFFSET, TEXT_WIDTH, TEXT_HEIGHT); + + for (i = 0; i < TEXT_HEIGHT / line_height + 2; i ++) { + const char *line; + int x; + + if (first_line + i >= NUM_TEXT_LINES) + break; + + if (*text[first_line + i] == '\0') + line = ""; + else + line = _(text[first_line + i]); + + x = TEXT_X_OFFSET + (TEXT_WIDTH - gdk_string_width (widget->style->font, line)) / 2; + + gdk_draw_string (priv->pixmap, widget->style->font, priv->clipped_gc, x, y, line); + + y += line_height; + } + + redraw_rect.x = TEXT_X_OFFSET; + redraw_rect.y = TEXT_Y_OFFSET; + redraw_rect.width = TEXT_WIDTH; + redraw_rect.height = TEXT_HEIGHT; + gtk_widget_draw (widget, &redraw_rect); + + priv->text_y_offset ++; + if (priv->text_y_offset > line_height * NUM_TEXT_LINES + TEXT_HEIGHT) + priv->text_y_offset = 0; + + return TRUE; +} + + +/* GtkObject methods. */ + +static void +impl_destroy (GtkObject *object) +{ + EShellAboutBox *about_box; + EShellAboutBoxPrivate *priv; + + about_box = E_SHELL_ABOUT_BOX (object); + priv = about_box->priv; + + if (priv->pixmap != NULL) { + gdk_pixmap_unref (priv->pixmap); + priv->pixmap = NULL; + } + + if (priv->text_background_pixmap != NULL) { + gdk_pixmap_unref (priv->text_background_pixmap); + priv->text_background_pixmap = NULL; + } + + if (priv->clipped_gc != NULL) { + gdk_gc_unref (priv->clipped_gc); + priv->clipped_gc = NULL; + } + + if (priv->timeout_id != -1) { + g_source_remove (priv->timeout_id); + priv->timeout_id = -1; + } + + g_free (priv); + + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + + +/* GtkWidget methods. */ + +static void +impl_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + requisition->width = WIDTH; + requisition->height = HEIGHT; +} + +static void +impl_realize (GtkWidget *widget) +{ + EShellAboutBox *about_box; + EShellAboutBoxPrivate *priv; + GdkPixbuf *background_pixbuf; + GdkRectangle clip_rectangle; + + (* GTK_WIDGET_CLASS (parent_class)->realize) (widget); + + about_box = E_SHELL_ABOUT_BOX (widget); + priv = about_box->priv; + + background_pixbuf = gdk_pixbuf_new_from_file (IMAGE_PATH); + g_assert (background_pixbuf != NULL); + g_assert (gdk_pixbuf_get_width (background_pixbuf) == WIDTH); + g_assert (gdk_pixbuf_get_height (background_pixbuf) == HEIGHT); + + g_assert (priv->pixmap == NULL); + priv->pixmap = gdk_pixmap_new (widget->window, WIDTH, HEIGHT, -1); + + gdk_pixbuf_render_to_drawable (background_pixbuf, priv->pixmap, widget->style->black_gc, + 0, 0, 0, 0, WIDTH, HEIGHT, + GDK_RGB_DITHER_MAX, 0, 0); + + g_assert (priv->clipped_gc == NULL); + priv->clipped_gc = gdk_gc_new (widget->window); + gdk_gc_copy (priv->clipped_gc, widget->style->black_gc); + + clip_rectangle.x = TEXT_X_OFFSET; + clip_rectangle.y = TEXT_Y_OFFSET; + clip_rectangle.width = TEXT_WIDTH; + clip_rectangle.height = TEXT_HEIGHT; + gdk_gc_set_clip_rectangle (priv->clipped_gc, & clip_rectangle); + + priv->text_background_pixmap = gdk_pixmap_new (widget->window, clip_rectangle.width, clip_rectangle.height, -1); + gdk_pixbuf_render_to_drawable (background_pixbuf, priv->text_background_pixmap, widget->style->black_gc, + TEXT_X_OFFSET, TEXT_Y_OFFSET, + 0, 0, TEXT_WIDTH, TEXT_HEIGHT, + GDK_RGB_DITHER_MAX, 0, 0); + + g_assert (priv->timeout_id == -1); + priv->timeout_id = g_timeout_add (ANIMATION_DELAY, timeout_callback, about_box); + + gdk_pixbuf_unref (background_pixbuf); +} + +static void +impl_unrealize (GtkWidget *widget) +{ + EShellAboutBox *about_box; + EShellAboutBoxPrivate *priv; + + about_box = E_SHELL_ABOUT_BOX (widget); + priv = about_box->priv; + + (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); + + g_assert (priv->clipped_gc != NULL); + gdk_gc_unref (priv->clipped_gc); + priv->clipped_gc = NULL; + + g_assert (priv->pixmap != NULL); + gdk_pixmap_unref (priv->pixmap); + priv->pixmap = NULL; + + if (priv->timeout_id != -1) { + g_source_remove (priv->timeout_id); + priv->timeout_id = -1; + } +} + +static void +impl_draw (GtkWidget *widget, + GdkRectangle *area) +{ + EShellAboutBox *about_box; + EShellAboutBoxPrivate *priv; + + if (! GTK_WIDGET_DRAWABLE (widget)) + return; + + about_box = E_SHELL_ABOUT_BOX (widget); + priv = about_box->priv; + + gdk_draw_pixmap (widget->window, widget->style->black_gc, priv->pixmap, + area->x, area->y, + area->x, area->y, area->width, area->height); +} + +static int +impl_expose_event (GtkWidget *widget, + GdkEventExpose *event) +{ + if (! GTK_WIDGET_DRAWABLE (widget)) + return FALSE; + + gtk_widget_draw (widget, &event->area); + + return TRUE; +} + + +static void +class_init (GtkObjectClass *object_class) +{ + GtkWidgetClass *widget_class; + + parent_class = gtk_type_class (PARENT_TYPE); + + object_class->destroy = impl_destroy; + + widget_class = GTK_WIDGET_CLASS (object_class); + widget_class->size_request = impl_size_request; + widget_class->realize = impl_realize; + widget_class->unrealize = impl_unrealize; + widget_class->draw = impl_draw; + widget_class->expose_event = impl_expose_event; +} + +static void +init (EShellAboutBox *shell_about_box) +{ + EShellAboutBoxPrivate *priv; + + priv = g_new (EShellAboutBoxPrivate, 1); + priv->pixmap = NULL; + priv->text_background_pixmap = NULL; + priv->clipped_gc = NULL; + priv->timeout_id = -1; + priv->text_y_offset = 0; + + shell_about_box->priv = priv; +} + + +void +e_shell_about_box_construct (EShellAboutBox *about_box) +{ + g_return_if_fail (about_box != NULL); + g_return_if_fail (E_IS_SHELL_ABOUT_BOX (about_box)); + + /* Nothing to do here. */ +} + +GtkWidget * +e_shell_about_box_new (void) +{ + EShellAboutBox *about_box; + + about_box = gtk_type_new (e_shell_about_box_get_type ()); + e_shell_about_box_construct (about_box); + + return GTK_WIDGET (about_box); +} + + +E_MAKE_TYPE (e_shell_about_box, "EShellAboutBox", EShellAboutBox, class_init, init, GTK_TYPE_EVENT_BOX) |