~ubuntu-branches/ubuntu/maverick/gimp/maverick-updates

« back to all changes in this revision

Viewing changes to app/gui/splash.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Holbach
  • Date: 2005-12-09 19:44:52 UTC
  • Revision ID: james.westby@ubuntu.com-20051209194452-yggpemjlofpjqyf4
Tags: upstream-2.2.9
ImportĀ upstreamĀ versionĀ 2.2.9

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* The GIMP -- an image manipulation program
 
2
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or modify
 
5
 * it under the terms of the GNU General Public License as published by
 
6
 * the Free Software Foundation; either version 2 of the License, or
 
7
 * (at your option) any later version.
 
8
 *
 
9
 * This program is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 * GNU General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU General Public License
 
15
 * along with this program; if not, write to the Free Software
 
16
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
17
 */
 
18
 
 
19
#include "config.h"
 
20
 
 
21
#include <stdlib.h>
 
22
 
 
23
#include <gtk/gtk.h>
 
24
 
 
25
#include "libgimpbase/gimpbase.h"
 
26
#include "libgimpcolor/gimpcolor.h"
 
27
 
 
28
#include "gui-types.h"
 
29
 
 
30
#include "splash.h"
 
31
 
 
32
#include "gimp-intl.h"
 
33
 
 
34
 
 
35
typedef struct
 
36
{
 
37
  GtkWidget      *window;
 
38
  GtkWidget      *area;
 
39
  gint            width;
 
40
  gint            height;
 
41
  GtkWidget      *progress;
 
42
  GdkPixmap      *pixmap;
 
43
  GdkGC          *gc;
 
44
  PangoLayout    *upper;
 
45
  gint            upper_x, upper_y;
 
46
  PangoLayout    *lower;
 
47
  gint            lower_x, lower_y;
 
48
} GimpSplash;
 
49
 
 
50
static GimpSplash *splash = NULL;
 
51
 
 
52
 
 
53
static void        splash_map             (void);
 
54
static gboolean    splash_area_expose     (GtkWidget      *widget,
 
55
                                           GdkEventExpose *event,
 
56
                                           GimpSplash     *splash);
 
57
static GdkPixbuf * splash_pick_from_dir   (const gchar    *dirname);
 
58
static void        splash_rectangle_union (GdkRectangle   *dest,
 
59
                                           PangoRectangle *pango_rect,
 
60
                                           gint            offset_x,
 
61
                                           gint            offset_y);
 
62
static gboolean    splash_average_bottom  (GtkWidget      *widget,
 
63
                                           GdkPixbuf      *pixbuf,
 
64
                                           GdkColor       *color);
 
65
 
 
66
 
 
67
/*  public functions  */
 
68
 
 
69
void
 
70
splash_create (void)
 
71
{
 
72
  GtkWidget      *frame;
 
73
  GtkWidget      *vbox;
 
74
  GdkPixbuf      *pixbuf;
 
75
  GdkScreen      *screen;
 
76
  PangoAttrList  *attrs;
 
77
  PangoAttribute *attr;
 
78
  GdkGCValues     values;
 
79
  gchar          *filename;
 
80
 
 
81
  g_return_if_fail (splash == NULL);
 
82
 
 
83
  filename = gimp_personal_rc_file ("gimp-splash.png");
 
84
  pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
 
85
  g_free (filename);
 
86
 
 
87
  if (! pixbuf)
 
88
    {
 
89
      filename = gimp_personal_rc_file ("splashes");
 
90
      pixbuf = splash_pick_from_dir (filename);
 
91
      g_free (filename);
 
92
    }
 
93
 
 
94
  if (! pixbuf)
 
95
    {
 
96
      filename = g_build_filename (gimp_data_directory (),
 
97
                                   "images", "gimp-splash.png", NULL);
 
98
      pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
 
99
      g_free (filename);
 
100
    }
 
101
 
 
102
  if (! pixbuf)
 
103
    {
 
104
      filename = g_build_filename (gimp_data_directory (), "splashes", NULL);
 
105
      pixbuf = splash_pick_from_dir (filename);
 
106
      g_free (filename);
 
107
    }
 
108
 
 
109
  if (! pixbuf)
 
110
    return;
 
111
 
 
112
  splash = g_new0 (GimpSplash, 1);
 
113
 
 
114
  splash->window =
 
115
    g_object_new (GTK_TYPE_WINDOW,
 
116
                  "type",            GTK_WINDOW_TOPLEVEL,
 
117
                  "type_hint",       GDK_WINDOW_TYPE_HINT_SPLASHSCREEN,
 
118
                  "title",           _("GIMP Startup"),
 
119
                  "role",            "gimp-startup",
 
120
                  "window_position", GTK_WIN_POS_CENTER,
 
121
                  "resizable",       FALSE,
 
122
                  NULL);
 
123
 
 
124
  g_signal_connect_swapped (splash->window, "delete_event",
 
125
                            G_CALLBACK (exit),
 
126
                            GINT_TO_POINTER (0));
 
127
 
 
128
  /* we don't want the splash screen to send the startup notification */
 
129
  gtk_window_set_auto_startup_notification (FALSE);
 
130
  g_signal_connect (splash->window, "map",
 
131
                    G_CALLBACK (splash_map),
 
132
                    NULL);
 
133
 
 
134
  screen = gtk_widget_get_screen (splash->window);
 
135
 
 
136
  splash->width  = MIN (gdk_pixbuf_get_width (pixbuf),
 
137
                        gdk_screen_get_width (screen));
 
138
  splash->height = MIN (gdk_pixbuf_get_height (pixbuf),
 
139
                        gdk_screen_get_height (screen));
 
140
 
 
141
  frame = gtk_frame_new (NULL);
 
142
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
 
143
  gtk_container_add (GTK_CONTAINER (splash->window), frame);
 
144
  gtk_widget_show (frame);
 
145
 
 
146
  vbox = gtk_vbox_new (FALSE, 0);
 
147
  gtk_container_add (GTK_CONTAINER (frame), vbox);
 
148
  gtk_widget_show (vbox);
 
149
 
 
150
  /*  prepare the drawing area  */
 
151
  splash->area = gtk_drawing_area_new ();
 
152
  gtk_box_pack_start_defaults (GTK_BOX (vbox), splash->area);
 
153
  gtk_widget_show (splash->area);
 
154
 
 
155
  gtk_widget_set_size_request (splash->area, splash->width, splash->height);
 
156
 
 
157
  gtk_widget_realize (splash->area);
 
158
 
 
159
  splash_average_bottom (splash->area, pixbuf, &values.foreground);
 
160
  splash->gc = gdk_gc_new_with_values (splash->area->window, &values,
 
161
                                       GDK_GC_FOREGROUND);
 
162
 
 
163
  splash->pixmap = gdk_pixmap_new (splash->area->window,
 
164
                                   splash->width, splash->height, -1);
 
165
  gdk_draw_pixbuf (splash->pixmap, splash->gc,
 
166
                   pixbuf, 0, 0, 0, 0, splash->width, splash->height,
 
167
                   GDK_RGB_DITHER_NORMAL, 0, 0);
 
168
  g_object_unref (pixbuf);
 
169
 
 
170
  g_signal_connect (splash->area, "expose_event",
 
171
                    G_CALLBACK (splash_area_expose),
 
172
                    splash);
 
173
 
 
174
  /*  create the pango layouts  */
 
175
  splash->upper = gtk_widget_create_pango_layout (splash->area, "");
 
176
  splash->lower = gtk_widget_create_pango_layout (splash->area, "");
 
177
 
 
178
  attrs = pango_attr_list_new ();
 
179
  attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
 
180
  attr->start_index = 0;
 
181
  attr->end_index   = -1;
 
182
  pango_attr_list_insert (attrs, attr);
 
183
 
 
184
  pango_layout_set_attributes (splash->upper, attrs);
 
185
  pango_attr_list_unref (attrs);
 
186
 
 
187
  /*  add a progress bar  */
 
188
  splash->progress = gtk_progress_bar_new ();
 
189
  gtk_box_pack_end (GTK_BOX (vbox), splash->progress, FALSE, FALSE, 0);
 
190
  gtk_widget_show (splash->progress);
 
191
 
 
192
  gtk_widget_show (splash->window);
 
193
 
 
194
  while (gtk_events_pending ())
 
195
    gtk_main_iteration ();
 
196
}
 
197
 
 
198
void
 
199
splash_destroy (void)
 
200
{
 
201
  if (! splash)
 
202
    return;
 
203
 
 
204
  gtk_widget_destroy (splash->window);
 
205
 
 
206
  g_object_unref (splash->gc);
 
207
  g_object_unref (splash->pixmap);
 
208
  g_object_unref (splash->upper);
 
209
  g_object_unref (splash->lower);
 
210
 
 
211
  g_free (splash);
 
212
  splash = NULL;
 
213
}
 
214
 
 
215
void
 
216
splash_update (const gchar *text1,
 
217
               const gchar *text2,
 
218
               gdouble      percentage)
 
219
{
 
220
  GdkRectangle    expose = { 0, 0, 0, 0 };
 
221
  PangoRectangle  ink;
 
222
  PangoRectangle  logical;
 
223
  gint            width;
 
224
  gint            height;
 
225
 
 
226
  if (! splash)
 
227
    return;
 
228
 
 
229
  width  = splash->area->allocation.width;
 
230
  height = splash->area->allocation.height;
 
231
 
 
232
  if (text1)
 
233
    {
 
234
      pango_layout_get_pixel_extents (splash->upper, &ink, NULL);
 
235
      splash_rectangle_union (&expose, &ink, splash->upper_x, splash->upper_y);
 
236
 
 
237
      pango_layout_set_text (splash->upper, text1, -1);
 
238
      pango_layout_get_pixel_extents (splash->upper, &ink, &logical);
 
239
 
 
240
      splash->upper_x = (width - logical.width) / 2;
 
241
      splash->upper_y = height - 2 * (logical.height + 6);
 
242
 
 
243
      splash_rectangle_union (&expose, &ink, splash->upper_x, splash->upper_y);
 
244
    }
 
245
 
 
246
  if (text2)
 
247
    {
 
248
      pango_layout_get_pixel_extents (splash->lower, &ink, NULL);
 
249
      splash_rectangle_union (&expose, &ink, splash->lower_x, splash->lower_y);
 
250
 
 
251
      pango_layout_set_text (splash->lower, text2, -1);
 
252
      pango_layout_get_pixel_extents (splash->lower, &ink, &logical);
 
253
 
 
254
      splash->lower_x = (width - logical.width) / 2;
 
255
      splash->lower_y = height - (logical.height + 6);
 
256
 
 
257
      splash_rectangle_union (&expose, &ink, splash->lower_x, splash->lower_y);
 
258
    }
 
259
 
 
260
  if (expose.width > 0 && expose.height > 0)
 
261
    gtk_widget_queue_draw_area (splash->area,
 
262
                                expose.x, expose.y,
 
263
                                expose.width, expose.height);
 
264
 
 
265
  gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (splash->progress),
 
266
                                 CLAMP (percentage, 0.0, 1.0));
 
267
 
 
268
  while (gtk_events_pending ())
 
269
    gtk_main_iteration ();
 
270
}
 
271
 
 
272
 
 
273
/*  private functions  */
 
274
 
 
275
static gboolean
 
276
splash_area_expose (GtkWidget      *widget,
 
277
                    GdkEventExpose *event,
 
278
                    GimpSplash     *splash)
 
279
{
 
280
  gdk_gc_set_clip_rectangle (splash->gc, &event->area);
 
281
 
 
282
  gdk_draw_drawable (widget->window, splash->gc,
 
283
                     splash->pixmap, 0, 0,
 
284
                     (widget->allocation.width  - splash->width)  / 2,
 
285
                     (widget->allocation.height - splash->height) / 2,
 
286
                     splash->width,
 
287
                     splash->height);
 
288
 
 
289
  gdk_draw_layout (widget->window, splash->gc,
 
290
                   splash->upper_x, splash->upper_y, splash->upper);
 
291
 
 
292
  gdk_draw_layout (widget->window, splash->gc,
 
293
                   splash->lower_x, splash->lower_y, splash->lower);
 
294
 
 
295
  return FALSE;
 
296
}
 
297
 
 
298
static void
 
299
splash_map (void)
 
300
{
 
301
  /*  Reenable startup notification after the splash has been shown
 
302
   *  so that the next window that is mapped sends the notification.
 
303
   */
 
304
   gtk_window_set_auto_startup_notification (TRUE);
 
305
}
 
306
 
 
307
static GdkPixbuf *
 
308
splash_pick_from_dir (const gchar *dirname)
 
309
{
 
310
  GdkPixbuf *pixbuf = NULL;
 
311
  GDir      *dir    = g_dir_open (dirname, 0, NULL);
 
312
 
 
313
  if (dir)
 
314
    {
 
315
      const gchar *entry;
 
316
      GList       *splashes = NULL;
 
317
 
 
318
      while ((entry = g_dir_read_name (dir)))
 
319
        splashes = g_list_prepend (splashes, g_strdup (entry));
 
320
 
 
321
      g_dir_close (dir);
 
322
 
 
323
      if (splashes)
 
324
        {
 
325
          gint32  i        = g_random_int_range (0, g_list_length (splashes));
 
326
          gchar  *filename = g_build_filename (dirname,
 
327
                                               g_list_nth_data (splashes, i),
 
328
                                               NULL);
 
329
 
 
330
          pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
 
331
          g_free (filename);
 
332
 
 
333
          g_list_foreach (splashes, (GFunc) g_free, NULL);
 
334
          g_list_free (splashes);
 
335
        }
 
336
    }
 
337
 
 
338
  return pixbuf;
 
339
}
 
340
 
 
341
static void
 
342
splash_rectangle_union (GdkRectangle   *dest,
 
343
                        PangoRectangle *pango_rect,
 
344
                        gint            offset_x,
 
345
                        gint            offset_y)
 
346
{
 
347
  GdkRectangle  rect;
 
348
 
 
349
  rect.x      = pango_rect->x + offset_x;
 
350
  rect.y      = pango_rect->y + offset_y;
 
351
  rect.width  = pango_rect->width;
 
352
  rect.height = pango_rect->height;
 
353
 
 
354
  if (dest->width > 0 && dest->height > 0)
 
355
    gdk_rectangle_union (dest, &rect, dest);
 
356
  else
 
357
    *dest = rect;
 
358
}
 
359
 
 
360
/* This function chooses a gray value for the text color, based on
 
361
 * the average intensity of the lower 60 rows of the splash image.
 
362
 */
 
363
static gboolean
 
364
splash_average_bottom (GtkWidget *widget,
 
365
                       GdkPixbuf *pixbuf,
 
366
                       GdkColor  *color)
 
367
{
 
368
  const guchar *pixels;
 
369
  gint          x, y;
 
370
  gint          width, height;
 
371
  gint          rowstride;
 
372
  gint          channels;
 
373
  gint          intensity;
 
374
  gint          count;
 
375
  guint         sum[3] = { 0, 0, 0 };
 
376
 
 
377
  g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), FALSE);
 
378
  g_return_val_if_fail (gdk_pixbuf_get_bits_per_sample (pixbuf) == 8, FALSE);
 
379
 
 
380
  width     = gdk_pixbuf_get_width (pixbuf);
 
381
  height    = gdk_pixbuf_get_height (pixbuf);
 
382
  rowstride = gdk_pixbuf_get_rowstride (pixbuf);
 
383
  channels  = gdk_pixbuf_get_n_channels (pixbuf);
 
384
  pixels    = gdk_pixbuf_get_pixels (pixbuf);
 
385
 
 
386
  y = MAX (0, height - 60);
 
387
  count = width * (height - y);
 
388
 
 
389
  pixels += y * rowstride;
 
390
 
 
391
  for (; y < height; y++)
 
392
    {
 
393
      const guchar *src = pixels;
 
394
 
 
395
      for (x = 0; x < width; x++)
 
396
        {
 
397
          sum[0] += src[0];
 
398
          sum[1] += src[1];
 
399
          sum[2] += src[2];
 
400
 
 
401
          src += channels;
 
402
        }
 
403
 
 
404
      pixels += rowstride;
 
405
    }
 
406
 
 
407
  intensity = GIMP_RGB_INTENSITY (sum[0] / count,
 
408
                                  sum[1] / count,
 
409
                                  sum[2] / count);
 
410
 
 
411
  intensity = CLAMP0255 (intensity > 127 ? intensity - 223 : intensity + 223);
 
412
 
 
413
  color->red = color->green = color->blue = (intensity << 8 | intensity);
 
414
 
 
415
  return gdk_colormap_alloc_color (gtk_widget_get_colormap (widget),
 
416
                                   color, FALSE, TRUE);
 
417
}