gnome-shell-3.6.3.1/src/st/st-bin.c

No issues found

  1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
  2 /*
  3  * st-bin.c: Basic container actor
  4  *
  5  * Copyright 2009 Intel Corporation.
  6  * Copyright 2009, 2010 Red Hat, Inc.
  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, see <http://www.gnu.org/licenses/>.
 19  */
 20 
 21 /**
 22  * SECTION:st-bin
 23  * @short_description: a simple container with one actor
 24  *
 25  * #StBin is a simple container capable of having only one
 26  * #ClutterActor as a child.
 27  *
 28  * #StBin inherits from #StWidget, so it is fully themable.
 29  */
 30 
 31 #ifdef HAVE_CONFIG_H
 32 #include "config.h"
 33 #endif
 34 
 35 #include <clutter/clutter.h>
 36 
 37 #include "st-bin.h"
 38 #include "st-enum-types.h"
 39 #include "st-private.h"
 40 
 41 #define ST_BIN_GET_PRIVATE(obj)       (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ST_TYPE_BIN, StBinPrivate))
 42 
 43 struct _StBinPrivate
 44 {
 45   ClutterActor *child;
 46 
 47   StAlign       x_align;
 48   StAlign       y_align;
 49 
 50   guint         x_fill : 1;
 51   guint         y_fill : 1;
 52 };
 53 
 54 enum
 55 {
 56   PROP_0,
 57 
 58   PROP_CHILD,
 59   PROP_X_ALIGN,
 60   PROP_Y_ALIGN,
 61   PROP_X_FILL,
 62   PROP_Y_FILL
 63 };
 64 
 65 static void clutter_container_iface_init (ClutterContainerIface *iface);
 66 
 67 G_DEFINE_TYPE_WITH_CODE (StBin, st_bin, ST_TYPE_WIDGET,
 68                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
 69                                                 clutter_container_iface_init));
 70 
 71 static void
 72 st_bin_add (ClutterContainer *container,
 73             ClutterActor     *actor)
 74 {
 75   st_bin_set_child (ST_BIN (container), actor);
 76 }
 77 
 78 static void
 79 st_bin_remove (ClutterContainer *container,
 80                ClutterActor     *actor)
 81 {
 82   StBinPrivate *priv = ST_BIN (container)->priv;
 83 
 84   if (priv->child == actor)
 85     st_bin_set_child (ST_BIN (container), NULL);
 86 }
 87 
 88 static void
 89 clutter_container_iface_init (ClutterContainerIface *iface)
 90 {
 91   iface->add = st_bin_add;
 92   iface->remove = st_bin_remove;
 93 }
 94 
 95 static void
 96 st_bin_allocate (ClutterActor          *self,
 97                  const ClutterActorBox *box,
 98                  ClutterAllocationFlags flags)
 99 {
100   StBinPrivate *priv = ST_BIN (self)->priv;
101 
102   clutter_actor_set_allocation (self, box, flags);
103 
104   if (priv->child && CLUTTER_ACTOR_IS_VISIBLE (priv->child))
105     {
106       StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (self));
107       ClutterActorBox childbox;
108       gdouble x_align_f, y_align_f;
109 
110       st_theme_node_get_content_box (theme_node, box, &childbox);
111       _st_get_align_factors (priv->x_align, priv->y_align,
112                              &x_align_f, &y_align_f);
113       clutter_actor_allocate_align_fill (priv->child, &childbox,
114                                          x_align_f, y_align_f,
115                                          priv->x_fill, priv->y_fill,
116                                          flags);
117     }
118 }
119 
120 static void
121 st_bin_get_preferred_width (ClutterActor *self,
122                             gfloat        for_height,
123                             gfloat       *min_width_p,
124                             gfloat       *natural_width_p)
125 {
126   StBinPrivate *priv = ST_BIN (self)->priv;
127   StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (self));
128 
129   st_theme_node_adjust_for_height (theme_node, &for_height);
130 
131   if (priv->child == NULL || !CLUTTER_ACTOR_IS_VISIBLE (priv->child))
132     {
133       if (min_width_p)
134         *min_width_p = 0;
135 
136       if (natural_width_p)
137         *natural_width_p = 0;
138     }
139   else
140     {
141       _st_actor_get_preferred_width (priv->child, for_height, priv->y_fill,
142                                      min_width_p,
143                                      natural_width_p);
144     }
145 
146   st_theme_node_adjust_preferred_width (theme_node, min_width_p, natural_width_p);
147 }
148 
149 static void
150 st_bin_get_preferred_height (ClutterActor *self,
151                              gfloat        for_width,
152                              gfloat       *min_height_p,
153                              gfloat       *natural_height_p)
154 {
155   StBinPrivate *priv = ST_BIN (self)->priv;
156   StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (self));
157 
158   st_theme_node_adjust_for_width (theme_node, &for_width);
159 
160   if (priv->child == NULL || !CLUTTER_ACTOR_IS_VISIBLE (priv->child))
161     {
162       if (min_height_p)
163         *min_height_p = 0;
164 
165       if (natural_height_p)
166         *natural_height_p = 0;
167     }
168   else
169     {
170       _st_actor_get_preferred_height (priv->child, for_width, priv->x_fill,
171                                       min_height_p,
172                                       natural_height_p);
173     }
174 
175   st_theme_node_adjust_preferred_height (theme_node, min_height_p, natural_height_p);
176 }
177 
178 static void
179 st_bin_dispose (GObject *gobject)
180 {
181   StBinPrivate *priv = ST_BIN (gobject)->priv;
182 
183   if (priv->child)
184     clutter_actor_destroy (priv->child);
185   g_assert (priv->child == NULL);
186 
187   G_OBJECT_CLASS (st_bin_parent_class)->dispose (gobject);
188 }
189 
190 static gboolean
191 st_bin_navigate_focus (StWidget         *widget,
192                        ClutterActor     *from,
193                        GtkDirectionType  direction)
194 {
195   StBinPrivate *priv = ST_BIN (widget)->priv;
196   ClutterActor *bin_actor = CLUTTER_ACTOR (widget);
197 
198   if (st_widget_get_can_focus (widget))
199     {
200       if (from && clutter_actor_contains (bin_actor, from))
201         return FALSE;
202 
203       if (CLUTTER_ACTOR_IS_MAPPED (bin_actor))
204         {
205           clutter_actor_grab_key_focus (bin_actor);
206           return TRUE;
207         }
208       else
209         {
210           return FALSE;
211         }
212     }
213   else if (priv->child && ST_IS_WIDGET (priv->child))
214     return st_widget_navigate_focus (ST_WIDGET (priv->child), from, direction, FALSE);
215   else
216     return FALSE;
217 }
218 
219 static void
220 st_bin_set_property (GObject      *gobject,
221                      guint         prop_id,
222                      const GValue *value,
223                      GParamSpec   *pspec)
224 {
225   StBin *bin = ST_BIN (gobject);
226 
227   switch (prop_id)
228     {
229     case PROP_CHILD:
230       st_bin_set_child (bin, g_value_get_object (value));
231       break;
232 
233     case PROP_X_ALIGN:
234       st_bin_set_alignment (bin,
235                             g_value_get_enum (value),
236                             bin->priv->y_align);
237       break;
238 
239     case PROP_Y_ALIGN:
240       st_bin_set_alignment (bin,
241                             bin->priv->x_align,
242                             g_value_get_enum (value));
243       break;
244 
245     case PROP_X_FILL:
246       st_bin_set_fill (bin,
247                        g_value_get_boolean (value),
248                        bin->priv->y_fill);
249       break;
250 
251     case PROP_Y_FILL:
252       st_bin_set_fill (bin,
253                        bin->priv->y_fill,
254                        g_value_get_boolean (value));
255       break;
256 
257     default:
258       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
259     }
260 }
261 
262 static void
263 st_bin_get_property (GObject    *gobject,
264                      guint       prop_id,
265                      GValue     *value,
266                      GParamSpec *pspec)
267 {
268   StBinPrivate *priv = ST_BIN (gobject)->priv;
269 
270   switch (prop_id)
271     {
272     case PROP_CHILD:
273       g_value_set_object (value, priv->child);
274       break;
275 
276     case PROP_X_FILL:
277       g_value_set_boolean (value, priv->x_fill);
278       break;
279 
280     case PROP_Y_FILL:
281       g_value_set_boolean (value, priv->y_fill);
282       break;
283 
284     case PROP_X_ALIGN:
285       g_value_set_enum (value, priv->x_align);
286       break;
287 
288     case PROP_Y_ALIGN:
289       g_value_set_enum (value, priv->y_align);
290       break;
291 
292     default:
293       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
294     }
295 }
296 
297 static void
298 st_bin_class_init (StBinClass *klass)
299 {
300   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
301   ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
302   StWidgetClass *widget_class = ST_WIDGET_CLASS (klass);
303   GParamSpec *pspec;
304 
305   g_type_class_add_private (klass, sizeof (StBinPrivate));
306 
307   gobject_class->set_property = st_bin_set_property;
308   gobject_class->get_property = st_bin_get_property;
309   gobject_class->dispose = st_bin_dispose;
310 
311   actor_class->get_preferred_width = st_bin_get_preferred_width;
312   actor_class->get_preferred_height = st_bin_get_preferred_height;
313   actor_class->allocate = st_bin_allocate;
314 
315   widget_class->navigate_focus = st_bin_navigate_focus;
316 
317   /**
318    * StBin:child:
319    *
320    * The child #ClutterActor of the #StBin container.
321    */
322   pspec = g_param_spec_object ("child",
323                                "Child",
324                                "The child of the Bin",
325                                CLUTTER_TYPE_ACTOR,
326                                ST_PARAM_READWRITE);
327   g_object_class_install_property (gobject_class, PROP_CHILD, pspec);
328 
329   /**
330    * StBin:x-align:
331    *
332    * The horizontal alignment of the #StBin child.
333    */
334   pspec = g_param_spec_enum ("x-align",
335                              "X Align",
336                              "The horizontal alignment",
337                              ST_TYPE_ALIGN,
338                              ST_ALIGN_MIDDLE,
339                              ST_PARAM_READWRITE);
340   g_object_class_install_property (gobject_class, PROP_X_ALIGN, pspec);
341 
342   /**
343    * StBin:y-align:
344    *
345    * The vertical alignment of the #StBin child.
346    */
347   pspec = g_param_spec_enum ("y-align",
348                              "Y Align",
349                              "The vertical alignment",
350                              ST_TYPE_ALIGN,
351                              ST_ALIGN_MIDDLE,
352                              ST_PARAM_READWRITE);
353   g_object_class_install_property (gobject_class, PROP_Y_ALIGN, pspec);
354 
355   /**
356    * StBin:x-fill:
357    *
358    * Whether the child should fill the horizontal allocation
359    */
360   pspec = g_param_spec_boolean ("x-fill",
361                                 "X Fill",
362                                 "Whether the child should fill the "
363                                 "horizontal allocation",
364                                 FALSE,
365                                 ST_PARAM_READWRITE);
366   g_object_class_install_property (gobject_class, PROP_X_FILL, pspec);
367 
368   /**
369    * StBin:y-fill:
370    *
371    * Whether the child should fill the vertical allocation
372    */
373   pspec = g_param_spec_boolean ("y-fill",
374                                 "Y Fill",
375                                 "Whether the child should fill the "
376                                 "vertical allocation",
377                                 FALSE,
378                                 ST_PARAM_READWRITE);
379   g_object_class_install_property (gobject_class, PROP_Y_FILL, pspec);
380 }
381 
382 static void
383 st_bin_init (StBin *bin)
384 {
385   bin->priv = ST_BIN_GET_PRIVATE (bin);
386 
387   bin->priv->x_align = ST_ALIGN_MIDDLE;
388   bin->priv->y_align = ST_ALIGN_MIDDLE;
389 }
390 
391 /**
392  * st_bin_new:
393  *
394  * Creates a new #StBin, a simple container for one child.
395  *
396  * Return value: the newly created #StBin actor
397  */
398 StWidget *
399 st_bin_new (void)
400 {
401   return g_object_new (ST_TYPE_BIN, NULL);
402 }
403 
404 /**
405  * st_bin_set_child:
406  * @bin: a #StBin
407  * @child: (allow-none): a #ClutterActor, or %NULL
408  *
409  * Sets @child as the child of @bin.
410  *
411  * If @bin already has a child, the previous child is removed.
412  */
413 void
414 st_bin_set_child (StBin        *bin,
415                   ClutterActor *child)
416 {
417   StBinPrivate *priv;
418 
419   g_return_if_fail (ST_IS_BIN (bin));
420   g_return_if_fail (child == NULL || CLUTTER_IS_ACTOR (child));
421 
422   priv = bin->priv;
423 
424   if (priv->child == child)
425     return;
426 
427   if (priv->child)
428     clutter_actor_remove_child (CLUTTER_ACTOR (bin), priv->child);
429 
430   priv->child = NULL;
431 
432   if (child)
433     {
434       priv->child = child;
435       clutter_actor_add_child (CLUTTER_ACTOR (bin), child);
436     }
437 
438   clutter_actor_queue_relayout (CLUTTER_ACTOR (bin));
439 
440   g_object_notify (G_OBJECT (bin), "child");
441 }
442 
443 /**
444  * st_bin_get_child:
445  * @bin: a #StBin
446  *
447  * Retrieves a pointer to the child of @bin.
448  *
449  * Return value: (transfer none): a #ClutterActor, or %NULL
450  */
451 ClutterActor *
452 st_bin_get_child (StBin *bin)
453 {
454   g_return_val_if_fail (ST_IS_BIN (bin), NULL);
455 
456   return bin->priv->child;
457 }
458 
459 /**
460  * st_bin_set_alignment:
461  * @bin: a #StBin
462  * @x_align: horizontal alignment
463  * @y_align: vertical alignment
464  *
465  * Sets the horizontal and vertical alignment of the child
466  * inside a #StBin.
467  */
468 void
469 st_bin_set_alignment (StBin  *bin,
470                       StAlign x_align,
471                       StAlign y_align)
472 {
473   StBinPrivate *priv;
474   gboolean changed = FALSE;
475 
476   g_return_if_fail (ST_IS_BIN (bin));
477 
478   priv = bin->priv;
479 
480   g_object_freeze_notify (G_OBJECT (bin));
481 
482   if (priv->x_align != x_align)
483     {
484       priv->x_align = x_align;
485       g_object_notify (G_OBJECT (bin), "x-align");
486       changed = TRUE;
487     }
488 
489   if (priv->y_align != y_align)
490     {
491       priv->y_align = y_align;
492       g_object_notify (G_OBJECT (bin), "y-align");
493       changed = TRUE;
494     }
495 
496   if (changed)
497     clutter_actor_queue_relayout (CLUTTER_ACTOR (bin));
498 
499   g_object_thaw_notify (G_OBJECT (bin));
500 }
501 
502 /**
503  * st_bin_get_alignment:
504  * @bin: a #StBin
505  * @x_align: return location for the horizontal alignment, or %NULL
506  * @y_align: return location for the vertical alignment, or %NULL
507  *
508  * Retrieves the horizontal and vertical alignment of the child
509  * inside a #StBin, as set by st_bin_set_alignment().
510  */
511 void
512 st_bin_get_alignment (StBin   *bin,
513                       StAlign *x_align,
514                       StAlign *y_align)
515 {
516   StBinPrivate *priv;
517 
518   g_return_if_fail (ST_IS_BIN (bin));
519 
520   priv = bin->priv;
521 
522   if (x_align)
523     *x_align = priv->x_align;
524 
525   if (y_align)
526     *y_align = priv->y_align;
527 }
528 
529 /**
530  * st_bin_set_fill:
531  * @bin: a #StBin
532  * @x_fill: %TRUE if the child should fill horizontally the @bin
533  * @y_fill: %TRUE if the child should fill vertically the @bin
534  *
535  * Sets whether the child of @bin should fill out the horizontal
536  * and/or vertical allocation of the parent
537  */
538 void
539 st_bin_set_fill (StBin   *bin,
540                  gboolean x_fill,
541                  gboolean y_fill)
542 {
543   StBinPrivate *priv;
544   gboolean changed = FALSE;
545 
546   g_return_if_fail (ST_IS_BIN (bin));
547 
548   priv = bin->priv;
549 
550   g_object_freeze_notify (G_OBJECT (bin));
551 
552   if (priv->x_fill != x_fill)
553     {
554       priv->x_fill = x_fill;
555       changed = TRUE;
556 
557       g_object_notify (G_OBJECT (bin), "x-fill");
558     }
559 
560   if (priv->y_fill != y_fill)
561     {
562       priv->y_fill = y_fill;
563       changed = TRUE;
564 
565       g_object_notify (G_OBJECT (bin), "y-fill");
566     }
567 
568   if (changed)
569     clutter_actor_queue_relayout (CLUTTER_ACTOR (bin));
570 
571   g_object_thaw_notify (G_OBJECT (bin));
572 }
573 
574 /**
575  * st_bin_get_fill:
576  * @bin: a #StBin
577  * @x_fill: (out): return location for the horizontal fill, or %NULL
578  * @y_fill: (out): return location for the vertical fill, or %NULL
579  *
580  * Retrieves the horizontal and vertical fill settings
581  */
582 void
583 st_bin_get_fill (StBin    *bin,
584                  gboolean *x_fill,
585                  gboolean *y_fill)
586 {
587   g_return_if_fail (ST_IS_BIN (bin));
588 
589   if (x_fill)
590     *x_fill = bin->priv->x_fill;
591 
592   if (y_fill)
593     *y_fill = bin->priv->y_fill;
594 }