source: trunk/third/evolution/shell/e-shell-about-box.c @ 18142

Revision 18142, 9.6 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18141, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2/* e-shell-about-box.c
3 *
4 * Copyright (C) 2001, 2002  Ximian, Inc.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public
16 * License along with this program; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
19 *
20 * Author: Ettore Perazzoli <ettore@ximian.com>
21 */
22
23#ifdef HAVE_CONFIG_H
24#include <config.h>
25#endif
26
27#include "e-shell-about-box.h"
28
29#include <gal/util/e-util.h>
30
31#include <gtk/gtkeventbox.h>
32#include <gdk-pixbuf/gdk-pixbuf.h>
33
34
35#define PARENT_TYPE gtk_event_box_get_type ()
36static GtkEventBoxClass *parent_class = NULL;
37
38static const char *text[] = {
39        "",
40        "Evolution " VERSION,
41        "Copyright 1999 - 2002 Ximian, Inc.",
42        "",
43        N_("Brought to you by"),
44        "",
45        "Seth Alves",
46        "Jacob Berkman",
47        "Kevin Breit",
48        "Anders Carlsson",
49        "Damon Chaplin",
50        "Zbigniew Chyla",
51        "Clifford R. Conover",
52        "Anna Dirks",
53        "Bob Doan",
54        "Miguel de Icaza",
55        "Radek Doulik",
56        "Arturo Espinoza",
57        "Larry Ewing",
58        "Nat Friedman",
59        "Alex Graveley",
60        "Bertrand Guiheneuf",
61        "Heath Harrelson",
62        "Iain Holmes",
63        "Mike Kestner",
64        "Tuomas Kuosmanen",
65        "Christopher J. Lahey",
66        "Miles Lane",
67        "Jason Leach",
68        "Timothy Lee",
69        "Matthew Loper",
70        "Michael MacDonald",
71        "Kjartan Maraas",
72        "Gerardo Marin",
73        "Michael Meeks",
74        "Federico Mena",
75        "Michael M. Morrison",
76        "Rodrigo Moya",
77        "Eskil Heyn Olsen",
78        "Gediminas Paulauskas",
79        "Jesse Pavel",
80        "Ettore Perazzoli",
81        "JP Rosevear",
82        "Jeffrey Stedfast",
83        "Jakub Steiner",
84        "Russell Steinthal",
85        "Peter Teichman",
86        "Chris Toshok",
87        "Jon Trowbridge",
88        "Luis Villa",
89        "Aaron Weber",
90        "Peter Williams",
91        "Dan Winship",
92        "Michael Zucchi"
93};
94#define NUM_TEXT_LINES (sizeof (text) / sizeof (*text))
95
96struct _EShellAboutBoxPrivate {
97        GdkPixmap *pixmap;
98        GdkPixmap *text_background_pixmap;
99        GdkGC *clipped_gc;
100        int text_y_offset;
101        int timeout_id;
102        const gchar **permuted_text;
103};
104
105
106#define ANIMATION_DELAY 40
107
108#define WIDTH  400
109#define HEIGHT 200
110
111#define TEXT_Y_OFFSET 57
112#define TEXT_X_OFFSET 60
113#define TEXT_WIDTH    (WIDTH - 2 * TEXT_X_OFFSET)
114#define TEXT_HEIGHT   90
115
116#define IMAGE_PATH  EVOLUTION_IMAGES "/about-box.png"
117
118
119
120static void
121permute_names (EShellAboutBox *about_box)
122{
123        EShellAboutBoxPrivate *priv = about_box->priv;
124        gint i, j;
125
126        srandom (time (NULL));
127       
128        for (i = 6; i < NUM_TEXT_LINES-1; ++i) {
129                const gchar *tmp;
130                j = i + random () % (NUM_TEXT_LINES - i);
131                if (i != j) {
132                        tmp = priv->permuted_text[i];
133                        priv->permuted_text[i] = priv->permuted_text[j];
134                        priv->permuted_text[j] = tmp;
135                }
136        }
137}
138
139/* The callback.  */
140
141static int
142timeout_callback (void *data)
143{
144        EShellAboutBox *about_box;
145        EShellAboutBoxPrivate *priv;
146        GdkRectangle redraw_rect;
147        GtkWidget *widget;
148        int line_height;
149        int first_line;
150        int y;
151        int i;
152
153        about_box = E_SHELL_ABOUT_BOX (data);
154        priv = about_box->priv;
155
156        widget = GTK_WIDGET (about_box);
157
158        line_height = widget->style->font->ascent + widget->style->font->descent;
159
160        if (priv->text_y_offset < TEXT_HEIGHT) {
161                y = TEXT_Y_OFFSET + (TEXT_HEIGHT - priv->text_y_offset);
162                first_line = 0;
163        } else {
164                y = TEXT_Y_OFFSET - ((priv->text_y_offset - TEXT_HEIGHT) % line_height);
165                first_line = (priv->text_y_offset - TEXT_HEIGHT) / line_height;
166        }
167
168        gdk_draw_pixmap (priv->pixmap, priv->clipped_gc, priv->text_background_pixmap,
169                         0, 0,
170                         TEXT_X_OFFSET, TEXT_Y_OFFSET, TEXT_WIDTH, TEXT_HEIGHT);
171
172        for (i = 0; i < TEXT_HEIGHT / line_height + 3; i ++) {
173                const char *line;
174                int x;
175
176                if (first_line + i >= NUM_TEXT_LINES)
177                        break;
178
179                if (*priv->permuted_text[first_line + i] == '\0')
180                        line = "";
181                else
182                        line = _(priv->permuted_text[first_line + i]);
183
184                x = TEXT_X_OFFSET + (TEXT_WIDTH - gdk_string_width (widget->style->font, line)) / 2;
185
186                gdk_draw_string (priv->pixmap, widget->style->font, priv->clipped_gc, x, y, line);
187
188                y += line_height;
189        }
190
191        redraw_rect.x      = TEXT_X_OFFSET;
192        redraw_rect.y      = TEXT_Y_OFFSET;
193        redraw_rect.width  = TEXT_WIDTH;
194        redraw_rect.height = TEXT_HEIGHT;
195        gtk_widget_draw (widget, &redraw_rect);
196
197        priv->text_y_offset ++;
198        if (priv->text_y_offset > line_height * NUM_TEXT_LINES + TEXT_HEIGHT) {
199                priv->text_y_offset = 0;
200                permute_names (about_box);
201        }
202
203        return TRUE;
204}
205
206
207/* GtkObject methods.  */
208
209static void
210impl_destroy (GtkObject *object)
211{
212        EShellAboutBox *about_box;
213        EShellAboutBoxPrivate *priv;
214
215        about_box = E_SHELL_ABOUT_BOX (object);
216        priv = about_box->priv;
217
218        if (priv->pixmap != NULL) {
219                gdk_pixmap_unref (priv->pixmap);
220                priv->pixmap = NULL;
221        }
222
223        if (priv->text_background_pixmap != NULL) {
224                gdk_pixmap_unref (priv->text_background_pixmap);
225                priv->text_background_pixmap = NULL;
226        }
227
228        if (priv->clipped_gc != NULL) {
229                gdk_gc_unref (priv->clipped_gc);
230                priv->clipped_gc = NULL;
231        }
232
233        if (priv->timeout_id != -1) {
234                g_source_remove (priv->timeout_id);
235                priv->timeout_id = -1;
236        }
237
238        g_free (priv->permuted_text);
239
240        g_free (priv);
241
242        (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
243}
244
245
246/* GtkWidget methods.  */
247
248static void
249impl_size_request (GtkWidget *widget,
250                   GtkRequisition *requisition)
251{
252        requisition->width = WIDTH;
253        requisition->height = HEIGHT;
254}
255
256static void
257impl_realize (GtkWidget *widget)
258{
259        EShellAboutBox *about_box;
260        EShellAboutBoxPrivate *priv;
261        GdkPixbuf *background_pixbuf;
262        GdkRectangle clip_rectangle;
263
264        (* GTK_WIDGET_CLASS (parent_class)->realize) (widget);
265
266        about_box = E_SHELL_ABOUT_BOX (widget);
267        priv = about_box->priv;
268
269        background_pixbuf = gdk_pixbuf_new_from_file (IMAGE_PATH);
270        g_assert (background_pixbuf != NULL);
271        g_assert (gdk_pixbuf_get_width (background_pixbuf) == WIDTH);
272        g_assert (gdk_pixbuf_get_height (background_pixbuf) == HEIGHT);
273
274        g_assert (priv->pixmap == NULL);
275        priv->pixmap = gdk_pixmap_new (widget->window, WIDTH, HEIGHT, -1);
276
277        gdk_pixbuf_render_to_drawable (background_pixbuf, priv->pixmap, widget->style->black_gc,
278                                       0, 0, 0, 0, WIDTH, HEIGHT,
279                                       GDK_RGB_DITHER_MAX, 0, 0);
280
281        g_assert (priv->clipped_gc == NULL);
282        priv->clipped_gc = gdk_gc_new (widget->window);
283        gdk_gc_copy (priv->clipped_gc, widget->style->black_gc);
284
285        clip_rectangle.x      = TEXT_X_OFFSET;
286        clip_rectangle.y      = TEXT_Y_OFFSET;
287        clip_rectangle.width  = TEXT_WIDTH;
288        clip_rectangle.height = TEXT_HEIGHT;
289        gdk_gc_set_clip_rectangle (priv->clipped_gc, & clip_rectangle);
290
291        priv->text_background_pixmap = gdk_pixmap_new (widget->window, clip_rectangle.width, clip_rectangle.height, -1);
292        gdk_pixbuf_render_to_drawable (background_pixbuf, priv->text_background_pixmap, widget->style->black_gc,
293                                       TEXT_X_OFFSET, TEXT_Y_OFFSET,
294                                       0, 0, TEXT_WIDTH, TEXT_HEIGHT,
295                                       GDK_RGB_DITHER_MAX, 0, 0);
296
297        g_assert (priv->timeout_id == -1);
298        priv->timeout_id = g_timeout_add (ANIMATION_DELAY, timeout_callback, about_box);
299
300        gdk_pixbuf_unref (background_pixbuf);
301}
302
303static void
304impl_unrealize (GtkWidget *widget)
305{
306        EShellAboutBox *about_box;
307        EShellAboutBoxPrivate *priv;
308
309        about_box = E_SHELL_ABOUT_BOX (widget);
310        priv = about_box->priv;
311
312        (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
313
314        g_assert (priv->clipped_gc != NULL);
315        gdk_gc_unref (priv->clipped_gc);
316        priv->clipped_gc = NULL;
317
318        g_assert (priv->pixmap != NULL);
319        gdk_pixmap_unref (priv->pixmap);
320        priv->pixmap = NULL;
321
322        if (priv->timeout_id != -1) {
323                g_source_remove (priv->timeout_id);
324                priv->timeout_id = -1;
325        }
326}
327
328static void
329impl_draw (GtkWidget *widget,
330           GdkRectangle *area)
331{
332        EShellAboutBox *about_box;
333        EShellAboutBoxPrivate *priv;
334
335        if (! GTK_WIDGET_DRAWABLE (widget))
336                return;
337
338        about_box = E_SHELL_ABOUT_BOX (widget);
339        priv = about_box->priv;
340
341        gdk_draw_pixmap (widget->window, widget->style->black_gc, priv->pixmap,
342                         area->x, area->y,
343                         area->x, area->y, area->width, area->height);
344}
345
346static int
347impl_expose_event (GtkWidget *widget,
348                   GdkEventExpose *event)
349{
350        if (! GTK_WIDGET_DRAWABLE (widget))
351                return FALSE;
352
353        gtk_widget_draw (widget, &event->area);
354
355        return TRUE;
356}
357
358
359static void
360class_init (GtkObjectClass *object_class)
361{
362        GtkWidgetClass *widget_class;
363
364        parent_class = gtk_type_class (PARENT_TYPE);
365
366        object_class->destroy = impl_destroy;
367
368        widget_class = GTK_WIDGET_CLASS (object_class);
369        widget_class->size_request = impl_size_request;
370        widget_class->realize      = impl_realize;
371        widget_class->unrealize    = impl_unrealize;
372        widget_class->draw         = impl_draw;
373        widget_class->expose_event = impl_expose_event;
374}
375
376static void
377init (EShellAboutBox *shell_about_box)
378{
379        EShellAboutBoxPrivate *priv;
380        gint i;
381
382        priv = g_new (EShellAboutBoxPrivate, 1);
383        priv->pixmap                 = NULL;
384        priv->text_background_pixmap = NULL;
385        priv->clipped_gc             = NULL;
386        priv->timeout_id             = -1;
387        priv->text_y_offset          = 0;
388
389        priv->permuted_text = g_new (const gchar *, NUM_TEXT_LINES);
390        for (i = 0; i < NUM_TEXT_LINES; ++i) {
391                priv->permuted_text[i] = text[i];
392        }
393
394        shell_about_box->priv = priv;
395
396        permute_names (shell_about_box);
397}
398
399
400void
401e_shell_about_box_construct (EShellAboutBox *about_box)
402{
403        g_return_if_fail (about_box != NULL);
404        g_return_if_fail (E_IS_SHELL_ABOUT_BOX (about_box));
405
406        /* Nothing to do here.  */
407}
408
409GtkWidget *
410e_shell_about_box_new (void)
411{
412        EShellAboutBox *about_box;
413
414        about_box = gtk_type_new (e_shell_about_box_get_type ());
415        e_shell_about_box_construct (about_box);
416
417        return GTK_WIDGET (about_box);
418}
419
420
421E_MAKE_TYPE (e_shell_about_box, "EShellAboutBox", EShellAboutBox, class_init, init, GTK_TYPE_EVENT_BOX)
Note: See TracBrowser for help on using the repository browser.