]> Pileus Git - ~andy/gtk/blob - gtk/gsimpleactionobserver.c
fdbe4bffd1e5d49d415afa6e6a7aebcbd04e7a29
[~andy/gtk] / gtk / gsimpleactionobserver.c
1 /*
2  * Copyright © 2012 Canonical Limited
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * licence or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful, but
10  * 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 Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
17  * USA.
18  *
19  * Authors: Ryan Lortie <desrt@desrt.ca>
20  */
21
22 #include "config.h"
23
24 #include "gsimpleactionobserver.h"
25 #include "gactionobservable.h"
26
27 typedef GObjectClass GSimpleActionObserverClass;
28 struct _GSimpleActionObserver
29 {
30   GObject parent_instance;
31
32   GActionGroup *action_group;
33   gchar *action_name;
34   GVariant *target;
35
36   gboolean can_activate;
37   gboolean active;
38   gboolean enabled;
39
40   gint reporting;
41 };
42
43 static void g_simple_action_observer_init_iface (GActionObserverInterface *iface);
44 G_DEFINE_TYPE_WITH_CODE (GSimpleActionObserver, g_simple_action_observer, G_TYPE_OBJECT,
45                          G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_OBSERVER, g_simple_action_observer_init_iface));
46
47 enum
48 {
49   PROP_0,
50   PROP_ACTIVE,
51   PROP_ENABLED,
52   N_PROPS
53 };
54
55 static GParamSpec *g_simple_action_observer_pspecs[N_PROPS];
56
57 static void
58 g_simple_action_observer_action_added (GActionObserver    *g_observer,
59                                        GActionObservable  *observable,
60                                        const gchar        *action_name,
61                                        const GVariantType *parameter_type,
62                                        gboolean            enabled,
63                                        GVariant           *state)
64 {
65   GSimpleActionObserver *observer = G_SIMPLE_ACTION_OBSERVER (g_observer);
66   gboolean active;
67
68   /* we can only activate if we have the correct type of parameter */
69   observer->can_activate = (observer->target == NULL && parameter_type == NULL) ||
70                             (observer->target != NULL && parameter_type != NULL &&
71                              g_variant_is_of_type (observer->target, parameter_type));
72
73   if (observer->can_activate)
74     {
75       if (observer->target != NULL && state != NULL)
76         active = g_variant_equal (state, observer->target);
77
78       else if (state != NULL && g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN))
79         active = g_variant_get_boolean (state);
80
81       else
82         active = FALSE;
83
84       if (active != observer->active)
85         {
86           observer->active = active;
87           observer->reporting++;
88           g_object_notify_by_pspec (G_OBJECT (observer), g_simple_action_observer_pspecs[PROP_ACTIVE]);
89           observer->reporting--;
90         }
91
92       if (enabled != observer->enabled)
93         {
94           observer->enabled = enabled;
95           g_object_notify_by_pspec (G_OBJECT (observer), g_simple_action_observer_pspecs[PROP_ENABLED]);
96         }
97     }
98 }
99
100 static void
101 g_simple_action_observer_action_enabled_changed (GActionObserver   *g_observer,
102                                                  GActionObservable *observable,
103                                                  const gchar       *action_name,
104                                                  gboolean           enabled)
105 {
106   GSimpleActionObserver *observer = G_SIMPLE_ACTION_OBSERVER (g_observer);
107
108   if (!observer->can_activate)
109     return;
110
111   if (enabled != observer->enabled)
112     {
113       observer->enabled = enabled;
114       g_object_notify_by_pspec (G_OBJECT (observer), g_simple_action_observer_pspecs[PROP_ENABLED]);
115     }
116 }
117
118 static void
119 g_simple_action_observer_action_state_changed (GActionObserver   *g_observer,
120                                                GActionObservable *observable,
121                                                const gchar       *action_name,
122                                                GVariant          *state)
123 {
124   GSimpleActionObserver *observer = G_SIMPLE_ACTION_OBSERVER (g_observer);
125   gboolean active = FALSE;
126
127   if (!observer->can_activate)
128     return;
129
130   if (observer->target)
131     active = g_variant_equal (state, observer->target);
132
133   else if (g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN))
134     active = g_variant_get_boolean (state);
135
136   if (active != observer->active)
137     {
138       observer->active = active;
139       observer->reporting++;
140       g_object_notify_by_pspec (G_OBJECT (observer), g_simple_action_observer_pspecs[PROP_ACTIVE]);
141       observer->reporting--;
142     }
143 }
144
145 static void
146 g_simple_action_observer_action_removed (GActionObserver   *g_observer,
147                                          GActionObservable *observable,
148                                          const gchar       *action_name)
149 {
150   GSimpleActionObserver *observer = G_SIMPLE_ACTION_OBSERVER (g_observer);
151
152   if (!observer->can_activate)
153     return;
154
155   observer->can_activate = FALSE;
156
157   if (observer->active)
158     {
159       observer->active = FALSE;
160       observer->reporting++;
161       g_object_notify_by_pspec (G_OBJECT (observer), g_simple_action_observer_pspecs[PROP_ACTIVE]);
162       observer->reporting--;
163     }
164
165   if (observer->enabled)
166     {
167       observer->enabled = FALSE;
168       g_object_notify_by_pspec (G_OBJECT (observer), g_simple_action_observer_pspecs[PROP_ENABLED]);
169     }
170 }
171
172 static void
173 g_simple_action_observer_get_property (GObject *object, guint prop_id,
174                                        GValue *value, GParamSpec *pspec)
175 {
176   GSimpleActionObserver *observer = G_SIMPLE_ACTION_OBSERVER (object);
177
178   switch (prop_id)
179     {
180     case PROP_ACTIVE:
181       g_value_set_boolean (value, observer->active);
182       break;
183
184     case PROP_ENABLED:
185       g_value_set_boolean (value, observer->enabled);
186       break;
187
188     default:
189       g_assert_not_reached ();
190     }
191 }
192
193 static void
194 g_simple_action_observer_finalize (GObject *object)
195 {
196   GSimpleActionObserver *observer = G_SIMPLE_ACTION_OBSERVER (object);
197
198   g_object_unref (observer->action_group);
199   g_free (observer->action_name);
200
201   if (observer->target)
202     g_variant_unref (observer->target);
203
204   G_OBJECT_CLASS (g_simple_action_observer_parent_class)
205     ->finalize (object);
206 }
207
208 static void
209 g_simple_action_observer_init (GSimpleActionObserver *observer)
210 {
211 }
212
213 static void
214 g_simple_action_observer_init_iface (GActionObserverInterface *iface)
215 {
216   iface->action_added = g_simple_action_observer_action_added;
217   iface->action_enabled_changed = g_simple_action_observer_action_enabled_changed;
218   iface->action_state_changed = g_simple_action_observer_action_state_changed;
219   iface->action_removed = g_simple_action_observer_action_removed;
220 }
221
222 static void
223 g_simple_action_observer_class_init (GObjectClass *class)
224 {
225   class->get_property = g_simple_action_observer_get_property;
226   class->finalize = g_simple_action_observer_finalize;
227
228   g_simple_action_observer_pspecs[PROP_ACTIVE] = g_param_spec_boolean ("active", "active", "active", FALSE,
229                                                                        G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
230   g_simple_action_observer_pspecs[PROP_ENABLED] = g_param_spec_boolean ("enabled", "enabled", "enabled", FALSE,
231                                                                         G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
232   g_object_class_install_properties (class, N_PROPS, g_simple_action_observer_pspecs);
233 }
234
235 GSimpleActionObserver *
236 g_simple_action_observer_new (GActionObservable *observable,
237                               const gchar       *action_name,
238                               GVariant          *target)
239 {
240   GSimpleActionObserver *observer;
241   const GVariantType *type;
242   gboolean enabled;
243   GVariant *state;
244
245   observer = g_object_new (G_TYPE_SIMPLE_ACTION_OBSERVER, NULL);
246   observer->action_group = g_object_ref (observable);
247   observer->action_name = g_strdup (action_name);
248   if (target)
249     observer->target = g_variant_ref_sink (target);
250
251   g_action_observable_register_observer (observable, action_name, G_ACTION_OBSERVER (observer));
252
253   if (g_action_group_query_action (observer->action_group, action_name, &enabled, &type, NULL, NULL, &state))
254     {
255       g_simple_action_observer_action_added (G_ACTION_OBSERVER (observer), observable,
256                                              action_name, type, enabled, state);
257       if (state)
258         g_variant_unref (state);
259     }
260
261   return observer;
262 }
263
264 void
265 g_simple_action_observer_activate (GSimpleActionObserver *observer)
266 {
267   g_return_if_fail (G_IS_SIMPLE_ACTION_OBSERVER (observer));
268
269   if (observer->can_activate && !observer->reporting)
270     g_action_group_activate_action (G_ACTION_GROUP (observer->action_group),
271                                     observer->action_name, observer->target);
272 }
273
274 gboolean
275 g_simple_action_observer_get_active (GSimpleActionObserver *observer)
276 {
277   g_return_val_if_fail (G_IS_SIMPLE_ACTION_OBSERVER (observer), FALSE);
278
279   return observer->active;
280 }
281
282 gboolean
283 g_simple_action_observer_get_enabled (GSimpleActionObserver *observer)
284 {
285   g_return_val_if_fail (G_IS_SIMPLE_ACTION_OBSERVER (observer), FALSE);
286
287   return observer->enabled;
288 }