~golfish/netbook-remix-launcher/desktop

« back to all changes in this revision

Viewing changes to src/launcher-background.c

  • Committer: Neil J. Patel
  • Date: 2008-04-16 11:31:15 UTC
  • Revision ID: njpatel@gmail.com-20080416113115-ztljg0qms79anijd
* Inital import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2007 Intel
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or
 
5
 * modify it under the terms of the GNU General Public
 
6
 * License as published by the Free Software Foundation; either
 
7
 * version 2 of the License, or (at your option) any later version.
 
8
 *
 
9
 * This library 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 GNU
 
12
 * Lesser General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU General Public
 
15
 * License along with this library; if not, write to the
 
16
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
17
 * Boston, MA 02111-1307, USA.
 
18
 *
 
19
 * Authored by Neil Jagdish Patel <njp@o-hand.com>
 
20
 *             Neil Jagdish Patel <neil.patel@canonical.com>
 
21
 *               - Updated to use default GNOME gconf keys
 
22
 *
 
23
 */
 
24
 
 
25
#include <glib.h>
 
26
#include <stdio.h>
 
27
#include <string.h>
 
28
#include <math.h>
 
29
 
 
30
#include <gconf/gconf.h>
 
31
#include <gconf/gconf-client.h>
 
32
 
 
33
#include "launcher-background.h"
 
34
#include "launcher-behave.h"
 
35
 
 
36
G_DEFINE_TYPE (LauncherBackground, launcher_background, CLUTTER_TYPE_GROUP)
 
37
 
 
38
#define LAUNCHER_BACKGROUND_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE(obj, \
 
39
        LAUNCHER_TYPE_BACKGROUND, LauncherBackgroundPrivate))
 
40
 
 
41
/* Gconf keys */
 
42
#define BG_PATH    "/desktop/gnome/background"
 
43
#define BG_FILE    BG_PATH "/picture_filename" /* string */
 
44
#define BG_OPTION  BG_PATH "/picture_options" 
 
45
                   /* none|wallpaper|centred|scaled|stretched|zoom */
 
46
 
 
47
#define BG_DEFAULT  PKGDATADIR "/default.svg"
 
48
 
 
49
struct _LauncherBackgroundPrivate
 
50
{
 
51
  ClutterActor *texture;
 
52
  ClutterActor *fade;
 
53
  
 
54
  gchar *filename;
 
55
  gchar *option;
 
56
 
 
57
  ClutterTimeline *timeline;
 
58
  ClutterAlpha *alpha;
 
59
  ClutterBehaviour *behave;
 
60
 
 
61
  gboolean fade_out;
 
62
};
 
63
 
 
64
/* 
 
65
 * Just load the file normally,if its larger than the stage, clip it */
 
66
static void
 
67
load_normal (const gchar *filename, ClutterActor *texture)
 
68
{
 
69
  GdkPixbuf *pixbuf = NULL;
 
70
  GError *error = NULL;
 
71
  gint width, height;
 
72
  gint subw = 0, subh = 0; 
 
73
 
 
74
  pixbuf = gdk_pixbuf_new_from_file (filename, &error);
 
75
 
 
76
  if (error)
 
77
  {
 
78
    g_warning (error->message);
 
79
    g_error_free (error);
 
80
    return;
 
81
  }
 
82
 
 
83
  width = gdk_pixbuf_get_width (pixbuf);
 
84
  height = gdk_pixbuf_get_height (pixbuf);
 
85
 
 
86
  if (width > CLUTTER_STAGE_WIDTH ())
 
87
    subw = CLUTTER_STAGE_WIDTH ();
 
88
  else
 
89
    subw = width;
 
90
 
 
91
  if (height > CLUTTER_STAGE_HEIGHT ())
 
92
    subh = CLUTTER_STAGE_HEIGHT ();
 
93
  else
 
94
    subh = height;
 
95
 
 
96
  if (subw && subh)
 
97
  {
 
98
    GdkPixbuf *temp = pixbuf;
 
99
 
 
100
    pixbuf = gdk_pixbuf_new_subpixbuf (temp, 0, 0, subw, subh);
 
101
    g_object_unref (temp);
 
102
  }
 
103
 
 
104
  clutter_texture_set_pixbuf (CLUTTER_TEXTURE (texture), pixbuf, NULL);
 
105
  clutter_actor_set_size (texture, 
 
106
                          CLUTTER_STAGE_WIDTH (),
 
107
                          CLUTTER_STAGE_HEIGHT ());
 
108
  clutter_actor_set_position (texture, 0, 0);
 
109
 
 
110
  g_object_unref (pixbuf);
 
111
}
 
112
 
 
113
/*
 
114
 * Simply return a stretched version of the image
 
115
 */
 
116
static void
 
117
load_stretched (const gchar *filename, ClutterActor *texture)
 
118
{
 
119
  GdkPixbuf *pixbuf = NULL;
 
120
  GError *error = NULL;
 
121
 
 
122
  pixbuf = gdk_pixbuf_new_from_file_at_scale (filename,
 
123
                                              CLUTTER_STAGE_WIDTH (),
 
124
                                              CLUTTER_STAGE_HEIGHT (),
 
125
                                              FALSE,
 
126
                                              &error);
 
127
  if (error)
 
128
  {
 
129
    g_warning (error->message);
 
130
    g_error_free (error);
 
131
  }
 
132
 
 
133
  clutter_texture_set_pixbuf (CLUTTER_TEXTURE (texture), pixbuf, NULL);
 
134
  clutter_actor_set_size (texture, 
 
135
                          CLUTTER_STAGE_WIDTH (),
 
136
                          CLUTTER_STAGE_HEIGHT ());
 
137
  clutter_actor_set_position (texture, 0, 0);
 
138
 
 
139
  g_object_unref (pixbuf);
 
140
}
 
141
 
 
142
/*
 
143
 * Center the image on the stage
 
144
 */
 
145
static void
 
146
load_centred (const gchar *filename, ClutterActor *texture)
 
147
{
 
148
  GdkPixbuf *pixbuf = NULL;
 
149
  GError *error = NULL;
 
150
  gint w, h, x, y;
 
151
 
 
152
  pixbuf = gdk_pixbuf_new_from_file (filename, &error);
 
153
 
 
154
  if (error)
 
155
  {
 
156
    g_warning (error->message);
 
157
    g_error_free (error);
 
158
    return;
 
159
  }
 
160
 
 
161
  clutter_texture_set_pixbuf (CLUTTER_TEXTURE (texture), pixbuf, NULL);
 
162
  
 
163
  w = gdk_pixbuf_get_width (pixbuf);
 
164
  h = gdk_pixbuf_get_height (pixbuf);
 
165
  x = (CLUTTER_STAGE_WIDTH ()/2) - (w/2);
 
166
  y = (CLUTTER_STAGE_HEIGHT ()/2) - (h/2);
 
167
 
 
168
  clutter_actor_set_size (texture, w, h);
 
169
  clutter_actor_set_position (texture, x, y);  
 
170
 
 
171
  g_object_unref (pixbuf);
 
172
}
 
173
 
 
174
/*
 
175
 * Load the image scaled with the correct aspect ratio 
 
176
 */
 
177
static void
 
178
load_scaled (const gchar *filename, ClutterActor *texture)
 
179
{
 
180
  GdkPixbuf *pixbuf = NULL;
 
181
  GError *error = NULL;
 
182
  gint w, h, x, y;
 
183
 
 
184
  pixbuf = gdk_pixbuf_new_from_file_at_scale (filename,
 
185
                                              CLUTTER_STAGE_WIDTH (),
 
186
                                              CLUTTER_STAGE_HEIGHT (),
 
187
                                              TRUE,
 
188
                                              &error);
 
189
  if (error)
 
190
  {
 
191
    g_warning (error->message);
 
192
    g_error_free (error);
 
193
  }
 
194
  
 
195
  clutter_texture_set_pixbuf (CLUTTER_TEXTURE (texture), pixbuf, NULL);
 
196
  
 
197
  w = gdk_pixbuf_get_width (pixbuf);
 
198
  h = gdk_pixbuf_get_height (pixbuf);
 
199
  x = (CLUTTER_STAGE_WIDTH ()/2) - (w/2);
 
200
  y = (CLUTTER_STAGE_HEIGHT ()/2) - (h/2);
 
201
 
 
202
  clutter_actor_set_size (texture, w, h);
 
203
  clutter_actor_set_position (texture, x, y);  
 
204
 
 
205
  g_object_unref (pixbuf);
 
206
}
 
207
 
 
208
/* 
 
209
 * Load the image, and then tile it until it covers the entire stage 
 
210
 */
 
211
static void
 
212
load_wallpaper (const gchar *filename, ClutterActor *texture)
 
213
{
 
214
  GdkPixbuf *pixbuf = NULL;
 
215
  GdkPixbuf *tiled = NULL;
 
216
  GError *error = NULL;
 
217
  gint w, h, x, y;
 
218
  gint rows, cols, r, c;
 
219
 
 
220
  pixbuf = gdk_pixbuf_new_from_file (filename, &error);
 
221
 
 
222
  if (error)
 
223
  {
 
224
    g_warning (error->message);
 
225
    g_error_free (error);
 
226
    return;
 
227
  }
 
228
 
 
229
  x = y = 0;
 
230
  rows = cols = 1;
 
231
  w = gdk_pixbuf_get_width (pixbuf);
 
232
  h = gdk_pixbuf_get_height (pixbuf);
 
233
 
 
234
  /* Find the number of rows and columns */
 
235
  if (w < CLUTTER_STAGE_WIDTH ())
 
236
    cols = (gint)ceil (CLUTTER_STAGE_WIDTH () / (gdouble)w);
 
237
  
 
238
  if (h < CLUTTER_STAGE_HEIGHT ())
 
239
    rows = (gint)ceil (CLUTTER_STAGE_HEIGHT () / (gdouble)h);
 
240
 
 
241
  /* Create the new pixbuf */
 
242
  tiled = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, w*cols, h*rows);
 
243
 
 
244
  /* For the number of rows, tile the cols */
 
245
  for (r = 0; r < rows; r++)
 
246
  {
 
247
    for (c = 0; c < cols; c++)
 
248
    {
 
249
      gdk_pixbuf_composite (pixbuf, tiled, x, y, w, h, x, y, 1, 1,
 
250
                            GDK_INTERP_BILINEAR, 255);
 
251
      x += w;
 
252
    }
 
253
    y += h;
 
254
    x = 0;
 
255
  }
 
256
 
 
257
  g_object_unref (pixbuf);
 
258
  
 
259
  clutter_texture_set_pixbuf (CLUTTER_TEXTURE (texture), tiled, NULL);
 
260
  clutter_actor_set_position (texture, 0, 0);
 
261
}
 
262
 
 
263
/* 
 
264
 * Use the filename and option values to create a background pixbuf, and set 
 
265
 * the internal tetxures pixbuf.
 
266
 * We try and get the smallest possible pixbuf to make sure we don't abuse
 
267
 * texture memory.
 
268
 */
 
269
static void
 
270
ensure_layout (LauncherBackground *bg)
 
271
{
 
272
  LauncherBackgroundPrivate *priv;
 
273
    
 
274
  g_return_if_fail (LAUNCHER_IS_BACKGROUND (bg));
 
275
  priv = bg->priv;
 
276
 
 
277
  if (priv->filename == NULL || strcmp (priv->filename, "default") == 0)
 
278
    priv->filename = g_strdup (BG_DEFAULT);
 
279
 
 
280
  if (priv->option == NULL)
 
281
    priv->option = g_strdup ("stretched");
 
282
 
 
283
  if (priv->option == NULL || strcmp (priv->option, "none") == 0)
 
284
  {
 
285
    load_normal (priv->filename, priv->texture);
 
286
  }
 
287
  else if (strcmp (priv->option, "wallpaper") == 0)
 
288
  {
 
289
    load_wallpaper (priv->filename, priv->texture);
 
290
  }
 
291
  else if (strcmp (priv->option, "centred") == 0)
 
292
  {
 
293
    load_centred (priv->filename, priv->texture);
 
294
  }
 
295
  else if (strcmp (priv->option, "scaled") == 0)
 
296
  {
 
297
    load_scaled (priv->filename, priv->texture);
 
298
  }
 
299
  else if (strcmp (priv->option, "zoom") == 0)
 
300
  {
 
301
    load_scaled (priv->filename, priv->texture);
 
302
  }
 
303
  else /* stretched */
 
304
  {
 
305
    load_stretched (priv->filename, priv->texture);
 
306
  }
 
307
 
 
308
  clutter_actor_queue_redraw (CLUTTER_ACTOR (bg));
 
309
}
 
310
 
 
311
/*
 
312
 * The animation function. At the moment, we just to a simple fade in/fade out
 
313
 */
 
314
static void
 
315
alpha_func (ClutterBehaviour   *behave,
 
316
            guint32             alpha_value,
 
317
            LauncherBackground *bg)
 
318
{
 
319
  LauncherBackgroundPrivate *priv;
 
320
  gfloat factor;
 
321
 
 
322
  g_return_if_fail (LAUNCHER_IS_BACKGROUND (bg));
 
323
  priv = bg->priv;
 
324
 
 
325
  factor = (gfloat)alpha_value / CLUTTER_ALPHA_MAX_ALPHA;
 
326
  
 
327
  if (priv->fade_out)
 
328
    clutter_actor_set_opacity (CLUTTER_ACTOR (bg), 255 - (255*factor));
 
329
  else
 
330
    clutter_actor_set_opacity (CLUTTER_ACTOR (bg), 255 * factor);
 
331
 
 
332
  clutter_actor_queue_redraw (CLUTTER_ACTOR (bg));
 
333
}
 
334
 
 
335
static void
 
336
on_timeline_completed (ClutterTimeline *timeline, LauncherBackground *bg)
 
337
{
 
338
  LauncherBackgroundPrivate *priv;
 
339
 
 
340
  g_return_if_fail (LAUNCHER_IS_BACKGROUND (bg));
 
341
  priv = bg->priv;
 
342
 
 
343
  if (priv->fade_out)
 
344
  {
 
345
    ensure_layout (bg);
 
346
    priv->fade_out = FALSE;
 
347
    clutter_timeline_start (priv->timeline);
 
348
  }
 
349
  else
 
350
  {
 
351
    priv->fade_out = TRUE;
 
352
  }
 
353
}
 
354
 
 
355
/* Gconf callbacks */
 
356
static void
 
357
on_bg_filename_changed (GConfClient        *client,
 
358
                        guint               cid,
 
359
                        GConfEntry         *entry,
 
360
                        LauncherBackground *bg)
 
361
{
 
362
  LauncherBackgroundPrivate *priv;
 
363
  GConfValue *value = NULL;
 
364
 
 
365
  g_return_if_fail (LAUNCHER_IS_BACKGROUND (bg));
 
366
  priv = bg->priv;
 
367
 
 
368
  value = gconf_entry_get_value (entry);
 
369
  if (priv->filename)
 
370
    g_free (priv->filename);
 
371
 
 
372
  priv->filename = g_strdup (gconf_value_get_string (value));
 
373
 
 
374
  clutter_timeline_start (priv->timeline);
 
375
}
 
376
 
 
377
static void
 
378
on_bg_option_changed (GConfClient        *client,
 
379
                      guint               cid,
 
380
                      GConfEntry         *entry,
 
381
                      LauncherBackground *bg)
 
382
{
 
383
  LauncherBackgroundPrivate *priv;
 
384
  GConfValue *value = NULL;
 
385
 
 
386
  g_return_if_fail (LAUNCHER_IS_BACKGROUND (bg));
 
387
  priv = bg->priv;
 
388
 
 
389
  value = gconf_entry_get_value (entry);
 
390
  if (priv->option)
 
391
    g_free (priv->option);
 
392
 
 
393
  priv->option = g_strdup (gconf_value_get_string (value));
 
394
 
 
395
  clutter_timeline_start (priv->timeline);
 
396
}
 
397
/* GObject functions */
 
398
static void
 
399
launcher_background_dispose (GObject *object)
 
400
{
 
401
  G_OBJECT_CLASS (launcher_background_parent_class)->dispose (object);
 
402
}
 
403
 
 
404
static void
 
405
launcher_background_finalize (GObject *background)
 
406
{
 
407
  LauncherBackgroundPrivate *priv;
 
408
  
 
409
  g_return_if_fail (LAUNCHER_IS_BACKGROUND (background));
 
410
  priv = LAUNCHER_BACKGROUND (background)->priv;
 
411
 
 
412
 
 
413
  G_OBJECT_CLASS (launcher_background_parent_class)->finalize (background);
 
414
}
 
415
 
 
416
 
 
417
static void
 
418
launcher_background_class_init (LauncherBackgroundClass *klass)
 
419
{
 
420
  GObjectClass *obj_class = G_OBJECT_CLASS (klass);
 
421
 
 
422
  obj_class->finalize = launcher_background_finalize;
 
423
  obj_class->dispose = launcher_background_dispose;
 
424
 
 
425
  g_type_class_add_private (obj_class, sizeof (LauncherBackgroundPrivate)); 
 
426
}
 
427
 
 
428
static void
 
429
launcher_background_init (LauncherBackground *background)
 
430
{
 
431
  LauncherBackgroundPrivate *priv;
 
432
  GConfClient *client = gconf_client_get_default ();
 
433
 
 
434
  priv = background->priv = LAUNCHER_BACKGROUND_GET_PRIVATE (background);
 
435
  priv->fade_out = TRUE;
 
436
 
 
437
  priv->texture = clutter_texture_new ();
 
438
  clutter_container_add_actor (CLUTTER_CONTAINER (background), priv->texture);
 
439
  clutter_actor_set_size (priv->texture, 
 
440
                          CLUTTER_STAGE_WIDTH (),
 
441
                          CLUTTER_STAGE_HEIGHT ());
 
442
  clutter_actor_set_position (priv->texture, 0, 0);
 
443
  clutter_actor_show (priv->texture);
 
444
 
 
445
  gconf_client_add_dir (client, BG_PATH, GCONF_CLIENT_PRELOAD_NONE, NULL);
 
446
 
 
447
  priv->filename = g_strdup (gconf_client_get_string (client, BG_FILE, NULL));
 
448
  gconf_client_notify_add (client, BG_FILE,
 
449
                           (GConfClientNotifyFunc)on_bg_filename_changed,
 
450
                           background, NULL, NULL);
 
451
  
 
452
  priv->option = g_strdup (gconf_client_get_string (client, BG_OPTION, NULL));
 
453
  gconf_client_notify_add (client, BG_OPTION,
 
454
                           (GConfClientNotifyFunc)on_bg_option_changed,
 
455
                           background, NULL, NULL);
 
456
  
 
457
 
 
458
  priv->timeline = clutter_timeline_new (40, 80);
 
459
  priv->alpha = clutter_alpha_new_full (priv->timeline,
 
460
                                        clutter_sine_inc_func,
 
461
                                        NULL, NULL);
 
462
  priv->behave = launcher_behave_new (priv->alpha, 
 
463
                                      (LauncherBehaveAlphaFunc)alpha_func,
 
464
                                      (gpointer)background);
 
465
 
 
466
  g_signal_connect (priv->timeline, "completed",
 
467
                    G_CALLBACK (on_timeline_completed), (gpointer)background);
 
468
 
 
469
  ensure_layout (background);
 
470
}
 
471
 
 
472
ClutterActor *
 
473
launcher_background_new (void)
 
474
{
 
475
  ClutterActor *background;
 
476
 
 
477
  background = g_object_new (LAUNCHER_TYPE_BACKGROUND,
 
478
                       NULL);
 
479
  return background;
 
480
}