~mterry/ubuntu/natty/gnome-shell/wip

« back to all changes in this revision

Viewing changes to src/st/st-texture-frame.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2009-10-12 22:44:00 UTC
  • mfrom: (1.1.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20091012224400-k91p42yvou07i525
Tags: 2.28.0-0ubuntu1
* New upstream version
* debian/control:
  - updated build requirement
* debian/patches/80_git_change_fix_alt_tab_ressource_usage.patch:
  - git change to fix ressources not being freed on alt-tab

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 
2
/*
 
3
 * st-texture-frame.h: Expandible texture actor
 
4
 *
 
5
 * Copyright 2007 OpenedHand
 
6
 * Copyright 2009 Intel Corporation.
 
7
 *
 
8
 * This program is free software; you can redistribute it and/or modify it
 
9
 * under the terms and conditions of the GNU Lesser General Public License,
 
10
 * version 2.1, as published by the Free Software Foundation.
 
11
 *
 
12
 * This program is distributed in the hope it will be useful, but WITHOUT ANY
 
13
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 
14
 * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
 
15
 * more details.
 
16
 *
 
17
 * You should have received a copy of the GNU Lesser General Public License
 
18
 * along with this program; if not, write to the Free Software Foundation,
 
19
 * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 
20
 * Boston, MA 02111-1307, USA.
 
21
 *
 
22
 */
 
23
 
 
24
/**
 
25
 * SECTION:st-texture-frame
 
26
 * @short_description: Stretch a texture to fit the entire allocation
 
27
 *
 
28
 * #StTextureFrame
 
29
 *
 
30
 */
 
31
 
 
32
#ifdef HAVE_CONFIG_H
 
33
#include "config.h"
 
34
#endif
 
35
 
 
36
#include <cogl/cogl.h>
 
37
 
 
38
#include "st-texture-frame.h"
 
39
#include "st-private.h"
 
40
 
 
41
enum
 
42
{
 
43
  PROP_0,
 
44
 
 
45
  PROP_PARENT_TEXTURE,
 
46
 
 
47
  PROP_TOP,
 
48
  PROP_RIGHT,
 
49
  PROP_BOTTOM,
 
50
  PROP_LEFT
 
51
};
 
52
 
 
53
G_DEFINE_TYPE (StTextureFrame, st_texture_frame, CLUTTER_TYPE_ACTOR);
 
54
 
 
55
#define ST_TEXTURE_FRAME_GET_PRIVATE(obj)     (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ST_TYPE_TEXTURE_FRAME, StTextureFramePrivate))
 
56
 
 
57
struct _StTextureFramePrivate
 
58
{
 
59
  ClutterTexture *parent_texture;
 
60
 
 
61
  gfloat          top;
 
62
  gfloat          right;
 
63
  gfloat          bottom;
 
64
  gfloat          left;
 
65
};
 
66
 
 
67
static void
 
68
st_texture_frame_get_preferred_width (ClutterActor *self,
 
69
                                      gfloat        for_height,
 
70
                                      gfloat       *min_width_p,
 
71
                                      gfloat       *natural_width_p)
 
72
{
 
73
  StTextureFramePrivate *priv = ST_TEXTURE_FRAME (self)->priv;
 
74
 
 
75
  if (G_UNLIKELY (priv->parent_texture == NULL))
 
76
    {
 
77
      if (min_width_p)
 
78
        *min_width_p = 0;
 
79
 
 
80
      if (natural_width_p)
 
81
        *natural_width_p = 0;
 
82
    }
 
83
  else
 
84
    {
 
85
      ClutterActorClass *klass;
 
86
 
 
87
      /* by directly querying the parent texture's class implementation
 
88
       * we are going around any override mechanism the parent texture
 
89
       * might have in place, and we ask directly for the original
 
90
       * preferred width
 
91
       */
 
92
      klass = CLUTTER_ACTOR_GET_CLASS (priv->parent_texture);
 
93
      klass->get_preferred_width (CLUTTER_ACTOR (priv->parent_texture),
 
94
                                  for_height,
 
95
                                  min_width_p,
 
96
                                  natural_width_p);
 
97
    }
 
98
}
 
99
 
 
100
static void
 
101
st_texture_frame_get_preferred_height (ClutterActor *self,
 
102
                                       gfloat        for_width,
 
103
                                       gfloat       *min_height_p,
 
104
                                       gfloat       *natural_height_p)
 
105
{
 
106
  StTextureFramePrivate *priv = ST_TEXTURE_FRAME (self)->priv;
 
107
 
 
108
  if (G_UNLIKELY (priv->parent_texture == NULL))
 
109
    {
 
110
      if (min_height_p)
 
111
        *min_height_p = 0;
 
112
 
 
113
      if (natural_height_p)
 
114
        *natural_height_p = 0;
 
115
    }
 
116
  else
 
117
    {
 
118
      ClutterActorClass *klass;
 
119
 
 
120
      /* by directly querying the parent texture's class implementation
 
121
       * we are going around any override mechanism the parent texture
 
122
       * might have in place, and we ask directly for the original
 
123
       * preferred height
 
124
       */
 
125
      klass = CLUTTER_ACTOR_GET_CLASS (priv->parent_texture);
 
126
      klass->get_preferred_height (CLUTTER_ACTOR (priv->parent_texture),
 
127
                                   for_width,
 
128
                                   min_height_p,
 
129
                                   natural_height_p);
 
130
    }
 
131
}
 
132
 
 
133
static void
 
134
st_texture_frame_paint (ClutterActor *self)
 
135
{
 
136
  StTextureFramePrivate *priv = ST_TEXTURE_FRAME (self)->priv;
 
137
  CoglHandle cogl_texture = COGL_INVALID_HANDLE;
 
138
  CoglHandle cogl_material = COGL_INVALID_HANDLE;
 
139
  ClutterActorBox box = { 0, };
 
140
  gfloat width, height;
 
141
  gfloat tex_width, tex_height;
 
142
  gfloat ex, ey;
 
143
  gfloat tx1, ty1, tx2, ty2;
 
144
  guint8 opacity;
 
145
 
 
146
  /* no need to paint stuff if we don't have a texture */
 
147
  if (G_UNLIKELY (priv->parent_texture == NULL))
 
148
    return;
 
149
 
 
150
  /* parent texture may have been hidden, so need to make sure it gets
 
151
   * realized
 
152
   */
 
153
  if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent_texture))
 
154
    clutter_actor_realize (CLUTTER_ACTOR (priv->parent_texture));
 
155
 
 
156
  cogl_texture = clutter_texture_get_cogl_texture (priv->parent_texture);
 
157
  if (cogl_texture == COGL_INVALID_HANDLE)
 
158
    return;
 
159
  cogl_material = clutter_texture_get_cogl_material (priv->parent_texture);
 
160
  if (cogl_material == COGL_INVALID_HANDLE)
 
161
    return;
 
162
 
 
163
  tex_width  = cogl_texture_get_width (cogl_texture);
 
164
  tex_height = cogl_texture_get_height (cogl_texture);
 
165
 
 
166
  clutter_actor_get_allocation_box (self, &box);
 
167
  width = box.x2 - box.x1;
 
168
  height = box.y2 - box.y1;
 
169
 
 
170
  tx1 = priv->left / tex_width;
 
171
  tx2 = (tex_width - priv->right) / tex_width;
 
172
  ty1 = priv->top / tex_height;
 
173
  ty2 = (tex_height - priv->bottom) / tex_height;
 
174
 
 
175
  ex = width - priv->right;
 
176
  if (ex < 0)
 
177
    ex = priv->right;           /* FIXME ? */
 
178
 
 
179
  ey = height - priv->bottom;
 
180
  if (ey < 0)
 
181
    ey = priv->bottom;          /* FIXME ? */
 
182
 
 
183
  opacity = clutter_actor_get_paint_opacity (self);
 
184
 
 
185
  /* Paint using the parent texture's material. It should already have
 
186
     the cogl texture set as the first layer */
 
187
  /* NB: for correct blending we need set a preumultiplied color here: */
 
188
  cogl_material_set_color4ub (cogl_material,
 
189
                              opacity, opacity, opacity, opacity);
 
190
  cogl_set_source (cogl_material);
 
191
 
 
192
  {
 
193
    GLfloat rectangles[] =
 
194
    {
 
195
      /* top left corner */
 
196
      0, 0, priv->left, priv->top,
 
197
      0.0, 0.0,
 
198
      tx1, ty1,
 
199
 
 
200
      /* top middle */
 
201
      priv->left, 0, ex, priv->top,
 
202
      tx1, 0.0,
 
203
      tx2, ty1,
 
204
 
 
205
      /* top right */
 
206
      ex, 0, width, priv->top,
 
207
      tx2, 0.0,
 
208
      1.0, ty1,
 
209
 
 
210
      /* mid left */
 
211
      0, priv->top, priv->left, ey,
 
212
      0.0, ty1,
 
213
      tx1, ty2,
 
214
 
 
215
      /* center */
 
216
      priv->left, priv->top, ex, ey,
 
217
      tx1, ty1,
 
218
      tx2, ty2,
 
219
 
 
220
      /* mid right */
 
221
      ex, priv->top, width, ey,
 
222
      tx2, ty1,
 
223
      1.0, ty2,
 
224
 
 
225
      /* bottom left */
 
226
      0, ey, priv->left, height,
 
227
      0.0, ty2,
 
228
      tx1, 1.0,
 
229
 
 
230
      /* bottom center */
 
231
      priv->left, ey, ex, height,
 
232
      tx1, ty2,
 
233
      tx2, 1.0,
 
234
 
 
235
      /* bottom right */
 
236
      ex, ey, width, height,
 
237
      tx2, ty2,
 
238
      1.0, 1.0
 
239
    };
 
240
 
 
241
    cogl_rectangles_with_texture_coords (rectangles, 9);
 
242
  }
 
243
}
 
244
 
 
245
static inline void
 
246
st_texture_frame_set_frame_internal (StTextureFrame *frame,
 
247
                                     gfloat          top,
 
248
                                     gfloat          right,
 
249
                                     gfloat          bottom,
 
250
                                     gfloat          left)
 
251
{
 
252
  StTextureFramePrivate *priv = frame->priv;
 
253
  GObject *gobject = G_OBJECT (frame);
 
254
  gboolean changed = FALSE;
 
255
 
 
256
  g_object_freeze_notify (gobject);
 
257
 
 
258
  if (priv->top != top)
 
259
    {
 
260
      priv->top = top;
 
261
      g_object_notify (gobject, "top");
 
262
      changed = TRUE;
 
263
    }
 
264
 
 
265
  if (priv->right != right)
 
266
    {
 
267
      priv->right = right;
 
268
      g_object_notify (gobject, "right");
 
269
      changed = TRUE;
 
270
    }
 
271
 
 
272
  if (priv->bottom != bottom)
 
273
    {
 
274
      priv->bottom = bottom;
 
275
      g_object_notify (gobject, "bottom");
 
276
      changed = TRUE;
 
277
    }
 
278
 
 
279
  if (priv->left != left)
 
280
    {
 
281
      priv->left = left;
 
282
      g_object_notify (gobject, "left");
 
283
      changed = TRUE;
 
284
    }
 
285
 
 
286
  if (changed && CLUTTER_ACTOR_IS_VISIBLE (frame))
 
287
    clutter_actor_queue_redraw (CLUTTER_ACTOR (frame));
 
288
 
 
289
  g_object_thaw_notify (gobject);
 
290
}
 
291
 
 
292
static void
 
293
st_texture_frame_set_property (GObject      *gobject,
 
294
                               guint         prop_id,
 
295
                               const GValue *value,
 
296
                               GParamSpec   *pspec)
 
297
{
 
298
  StTextureFrame *frame = ST_TEXTURE_FRAME (gobject);
 
299
  StTextureFramePrivate *priv = frame->priv;
 
300
 
 
301
  switch (prop_id)
 
302
    {
 
303
    case PROP_PARENT_TEXTURE:
 
304
      st_texture_frame_set_parent_texture (frame,
 
305
                                           g_value_get_object (value));
 
306
      break;
 
307
 
 
308
    case PROP_TOP:
 
309
      st_texture_frame_set_frame_internal (frame,
 
310
                                           g_value_get_float (value),
 
311
                                           priv->right,
 
312
                                           priv->bottom,
 
313
                                           priv->left);
 
314
      break;
 
315
 
 
316
    case PROP_RIGHT:
 
317
      st_texture_frame_set_frame_internal (frame,
 
318
                                           priv->top,
 
319
                                           g_value_get_float (value),
 
320
                                           priv->bottom,
 
321
                                           priv->left);
 
322
      break;
 
323
 
 
324
    case PROP_BOTTOM:
 
325
      st_texture_frame_set_frame_internal (frame,
 
326
                                           priv->top,
 
327
                                           priv->right,
 
328
                                           g_value_get_float (value),
 
329
                                           priv->left);
 
330
      break;
 
331
 
 
332
    case PROP_LEFT:
 
333
      st_texture_frame_set_frame_internal (frame,
 
334
                                           priv->top,
 
335
                                           priv->right,
 
336
                                           priv->bottom,
 
337
                                           g_value_get_float (value));
 
338
      break;
 
339
 
 
340
    default:
 
341
      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
 
342
      break;
 
343
    }
 
344
}
 
345
 
 
346
static void
 
347
st_texture_frame_get_property (GObject    *gobject,
 
348
                               guint       prop_id,
 
349
                               GValue     *value,
 
350
                               GParamSpec *pspec)
 
351
{
 
352
  StTextureFramePrivate *priv = ST_TEXTURE_FRAME (gobject)->priv;
 
353
 
 
354
  switch (prop_id)
 
355
    {
 
356
    case PROP_PARENT_TEXTURE:
 
357
      g_value_set_object (value, priv->parent_texture);
 
358
      break;
 
359
 
 
360
    case PROP_LEFT:
 
361
      g_value_set_float (value, priv->left);
 
362
      break;
 
363
 
 
364
    case PROP_TOP:
 
365
      g_value_set_float (value, priv->top);
 
366
      break;
 
367
 
 
368
    case PROP_RIGHT:
 
369
      g_value_set_float (value, priv->right);
 
370
      break;
 
371
 
 
372
    case PROP_BOTTOM:
 
373
      g_value_set_float (value, priv->bottom);
 
374
      break;
 
375
 
 
376
    default:
 
377
      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
 
378
      break;
 
379
    }
 
380
}
 
381
 
 
382
static void
 
383
st_texture_frame_dispose (GObject *gobject)
 
384
{
 
385
  StTextureFramePrivate *priv = ST_TEXTURE_FRAME (gobject)->priv;
 
386
 
 
387
  if (priv->parent_texture)
 
388
    {
 
389
      g_object_unref (priv->parent_texture);
 
390
      priv->parent_texture = NULL;
 
391
    }
 
392
 
 
393
  G_OBJECT_CLASS (st_texture_frame_parent_class)->dispose (gobject);
 
394
}
 
395
 
 
396
static void
 
397
st_texture_frame_class_init (StTextureFrameClass *klass)
 
398
{
 
399
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
400
  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
 
401
  GParamSpec *pspec;
 
402
 
 
403
  g_type_class_add_private (gobject_class, sizeof (StTextureFramePrivate));
 
404
 
 
405
  actor_class->get_preferred_width =
 
406
    st_texture_frame_get_preferred_width;
 
407
  actor_class->get_preferred_height =
 
408
    st_texture_frame_get_preferred_height;
 
409
  actor_class->paint = st_texture_frame_paint;
 
410
 
 
411
  gobject_class->set_property = st_texture_frame_set_property;
 
412
  gobject_class->get_property = st_texture_frame_get_property;
 
413
  gobject_class->dispose = st_texture_frame_dispose;
 
414
 
 
415
  pspec = g_param_spec_object ("parent-texture",
 
416
                               "Parent Texture",
 
417
                               "The parent ClutterTexture",
 
418
                               CLUTTER_TYPE_TEXTURE,
 
419
                               ST_PARAM_READWRITE |
 
420
                               G_PARAM_CONSTRUCT);
 
421
  g_object_class_install_property (gobject_class, PROP_PARENT_TEXTURE, pspec);
 
422
 
 
423
  pspec = g_param_spec_float ("left",
 
424
                              "Left",
 
425
                              "Left offset",
 
426
                              0, G_MAXFLOAT,
 
427
                              0,
 
428
                              ST_PARAM_READWRITE);
 
429
  g_object_class_install_property (gobject_class, PROP_LEFT, pspec);
 
430
 
 
431
  pspec = g_param_spec_float ("top",
 
432
                              "Top",
 
433
                              "Top offset",
 
434
                              0, G_MAXFLOAT,
 
435
                              0,
 
436
                              ST_PARAM_READWRITE);
 
437
  g_object_class_install_property (gobject_class, PROP_TOP, pspec);
 
438
 
 
439
  pspec = g_param_spec_float ("bottom",
 
440
                              "Bottom",
 
441
                              "Bottom offset",
 
442
                              0, G_MAXFLOAT,
 
443
                              0,
 
444
                              ST_PARAM_READWRITE);
 
445
  g_object_class_install_property (gobject_class, PROP_BOTTOM, pspec);
 
446
 
 
447
  pspec = g_param_spec_float ("right",
 
448
                              "Right",
 
449
                              "Right offset",
 
450
                              0, G_MAXFLOAT,
 
451
                              0,
 
452
                              ST_PARAM_READWRITE);
 
453
  g_object_class_install_property (gobject_class, PROP_RIGHT, pspec);
 
454
}
 
455
 
 
456
static void
 
457
st_texture_frame_init (StTextureFrame *self)
 
458
{
 
459
  StTextureFramePrivate *priv;
 
460
 
 
461
  self->priv = priv = ST_TEXTURE_FRAME_GET_PRIVATE (self);
 
462
}
 
463
 
 
464
/**
 
465
 * st_texture_frame_new:
 
466
 * @texture: a #ClutterTexture or %NULL
 
467
 * @left: left margin preserving its content
 
468
 * @top: top margin preserving its content
 
469
 * @right: right margin preserving its content
 
470
 * @bottom: bottom margin preserving its content
 
471
 *
 
472
 * A #StTextureFrame is a specialized texture that efficiently clones
 
473
 * an area of the given @texture while keeping preserving portions of the
 
474
 * same texture.
 
475
 *
 
476
 * A #StTextureFrame can be used to make a rectangular texture fit a
 
477
 * given size without stretching its borders.
 
478
 *
 
479
 * Return value: the newly created #StTextureFrame
 
480
 */
 
481
ClutterActor*
 
482
st_texture_frame_new (ClutterTexture *texture,
 
483
                      gfloat          top,
 
484
                      gfloat          right,
 
485
                      gfloat          bottom,
 
486
                      gfloat          left)
 
487
{
 
488
  g_return_val_if_fail (texture == NULL || CLUTTER_IS_TEXTURE (texture), NULL);
 
489
 
 
490
  return g_object_new (ST_TYPE_TEXTURE_FRAME,
 
491
                       "parent-texture", texture,
 
492
                       "top", top,
 
493
                       "right", right,
 
494
                       "bottom", bottom,
 
495
                       "left", left,
 
496
                       NULL);
 
497
}
 
498
 
 
499
/**
 
500
 * st_texture_frame_get_parent_texture:
 
501
 * @frame: A #StTextureFrame
 
502
 *
 
503
 * Return the texture used by the #StTextureFrame
 
504
 *
 
505
 * Returns: (transfer none): a #ClutterTexture owned by the #StTextureFrame
 
506
 */
 
507
ClutterTexture *
 
508
st_texture_frame_get_parent_texture (StTextureFrame *frame)
 
509
{
 
510
  g_return_val_if_fail (ST_IS_TEXTURE_FRAME (frame), NULL);
 
511
 
 
512
  return frame->priv->parent_texture;
 
513
}
 
514
 
 
515
/**
 
516
 * st_texture_frame_set_parent_texture:
 
517
 * @frame: A #StTextureFrame
 
518
 * @texture: A #ClutterTexture
 
519
 *
 
520
 * Set the #ClutterTexture used by this #StTextureFrame
 
521
 *
 
522
 */
 
523
void
 
524
st_texture_frame_set_parent_texture (StTextureFrame *frame,
 
525
                                     ClutterTexture *texture)
 
526
{
 
527
  StTextureFramePrivate *priv;
 
528
  gboolean was_visible;
 
529
 
 
530
  g_return_if_fail (ST_IS_TEXTURE_FRAME (frame));
 
531
  g_return_if_fail (texture == NULL || CLUTTER_IS_TEXTURE (texture));
 
532
 
 
533
  priv = frame->priv;
 
534
 
 
535
  was_visible = CLUTTER_ACTOR_IS_VISIBLE (frame);
 
536
 
 
537
  if (priv->parent_texture == texture)
 
538
    return;
 
539
 
 
540
  if (priv->parent_texture)
 
541
    {
 
542
      g_object_unref (priv->parent_texture);
 
543
      priv->parent_texture = NULL;
 
544
 
 
545
      if (was_visible)
 
546
        clutter_actor_hide (CLUTTER_ACTOR (frame));
 
547
    }
 
548
 
 
549
  if (texture)
 
550
    {
 
551
      priv->parent_texture = g_object_ref_sink (texture);
 
552
 
 
553
      if (was_visible && CLUTTER_ACTOR_IS_VISIBLE (priv->parent_texture))
 
554
        clutter_actor_show (CLUTTER_ACTOR (frame));
 
555
    }
 
556
 
 
557
  clutter_actor_queue_relayout (CLUTTER_ACTOR (frame));
 
558
 
 
559
  g_object_notify (G_OBJECT (frame), "parent-texture");
 
560
}
 
561
 
 
562
/**
 
563
 * st_texture_frame_set_frame:
 
564
 * @frame: A #StTextureFrame
 
565
 * @top: width of the top slice
 
566
 * @right: width of the right slice
 
567
 * @bottom: width of the bottom slice
 
568
 * @left: width of the left slice
 
569
 *
 
570
 * Set the slice lines of the specified frame. The slices are calculated as
 
571
 * widths from the edge of the frame.
 
572
 *
 
573
 */
 
574
void
 
575
st_texture_frame_set_frame (StTextureFrame *frame,
 
576
                            gfloat          top,
 
577
                            gfloat          right,
 
578
                            gfloat          bottom,
 
579
                            gfloat          left)
 
580
{
 
581
  g_return_if_fail (ST_IS_TEXTURE_FRAME (frame));
 
582
 
 
583
  st_texture_frame_set_frame_internal (frame, top, right, bottom, left);
 
584
}
 
585
 
 
586
/**
 
587
 * st_texture_frame_get_frame:
 
588
 * @frame: A #StTextureFrame
 
589
 * @top: width of the top slice
 
590
 * @right: width of the right slice
 
591
 * @bottom: width of the bottom slice
 
592
 * @left: width of the left slice
 
593
 *
 
594
 * Retrieve the current slice lines from the specified frame.
 
595
 *
 
596
 */
 
597
void
 
598
st_texture_frame_get_frame (StTextureFrame *frame,
 
599
                            gfloat         *top,
 
600
                            gfloat         *right,
 
601
                            gfloat         *bottom,
 
602
                            gfloat         *left)
 
603
{
 
604
  StTextureFramePrivate *priv;
 
605
 
 
606
  g_return_if_fail (ST_IS_TEXTURE_FRAME (frame));
 
607
 
 
608
  priv = frame->priv;
 
609
 
 
610
  if (top)
 
611
    *top = priv->top;
 
612
 
 
613
  if (right)
 
614
    *right = priv->right;
 
615
 
 
616
  if (bottom)
 
617
    *bottom = priv->bottom;
 
618
 
 
619
  if (left)
 
620
    *left = priv->left;
 
621
}