Bug Summary

File:ctk/ctkactionhelper.c
Warning:line 253, column 45
Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name ctkactionhelper.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/ctk -resource-dir /usr/lib/llvm-16/lib/clang/16 -D HAVE_CONFIG_H -I . -I .. -D G_LOG_DOMAIN="Ctk" -D G_LOG_USE_STRUCTURED=1 -D CTK_VERSION="3.25.5" -D CTK_BINARY_VERSION="3.0.0" -D CTK_COMPILATION -D CTK_PRINT_BACKEND_ENABLE_UNSUPPORTED -D CTK_LIBDIR="/usr/lib" -D CTK_LOCALEDIR="/usr/share/locale" -D CTK_DATADIR="/usr/share" -D CTK_DATA_PREFIX="/usr" -D CTK_SYSCONFDIR="/usr/etc" -D CTK_HOST="x86_64-pc-linux-gnu" -D CTK_PRINT_BACKENDS="file,cups" -D X11_DATA_PREFIX="/usr" -D ISO_CODES_PREFIX="" -I .. -I ../ctk -I .. -I ../cdk -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -D G_ENABLE_DEBUG -D G_ENABLE_CONSISTENCY_CHECKS -D GLIB_MIN_REQUIRED_VERSION=GLIB_VERSION_2_66 -D GLIB_MAX_ALLOWED_VERSION=GLIB_VERSION_2_66 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/atk-1.0 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/gio-unix-2.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/pango-1.0 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -D PIC -internal-isystem /usr/lib/llvm-16/lib/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/ctk -ferror-limit 19 -fvisibility=hidden -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-09-19-173409-43638-1 -x c ctkactionhelper.c
1/*
2 * Copyright © 2012 Canonical Limited
3 *
4 * This library 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, see <http://www.gnu.org/licenses/>.
16 *
17 * Authors: Ryan Lortie <desrt@desrt.ca>
18 */
19
20#include "ctkactionhelper.h"
21#include "ctkactionobservable.h"
22
23#include "ctkwidget.h"
24#include "ctkwidgetprivate.h"
25#include "ctkdebug.h"
26#include "ctkmodelbutton.h"
27#include "ctktypebuiltins.h"
28
29#include <string.h>
30
31typedef struct
32{
33 GActionGroup *group;
34
35 GHashTable *watchers;
36} CtkActionHelperGroup;
37
38static void ctk_action_helper_action_added (CtkActionHelper *helper,
39 gboolean enabled,
40 const GVariantType *parameter_type,
41 GVariant *state,
42 gboolean should_emit_signals);
43
44static void ctk_action_helper_action_removed (CtkActionHelper *helper,
45 gboolean should_emit_signals);
46
47static void ctk_action_helper_action_enabled_changed (CtkActionHelper *helper,
48 gboolean enabled);
49
50static void ctk_action_helper_action_state_changed (CtkActionHelper *helper,
51 GVariant *new_state);
52
53typedef GObjectClass CtkActionHelperClass;
54
55struct _CtkActionHelper
56{
57 GObject parent_instance;
58
59 CtkWidget *widget;
60
61 CtkActionHelperGroup *group;
62
63 CtkActionMuxer *action_context;
64 gchar *action_name;
65
66 GVariant *target;
67
68 gboolean can_activate;
69 gboolean enabled;
70 gboolean active;
71
72 CtkButtonRole role;
73
74 gint reporting;
75};
76
77enum
78{
79 PROP_0,
80 PROP_ENABLED,
81 PROP_ACTIVE,
82 PROP_ROLE,
83 N_PROPS
84};
85
86static GParamSpec *ctk_action_helper_pspecs[N_PROPS];
87
88static void ctk_action_helper_observer_iface_init (CtkActionObserverInterface *iface);
89
90G_DEFINE_TYPE_WITH_CODE (CtkActionHelper, ctk_action_helper, G_TYPE_OBJECT,static void ctk_action_helper_init (CtkActionHelper *self); static
void ctk_action_helper_class_init (CtkActionHelperClass *klass
); static GType ctk_action_helper_get_type_once (void); static
gpointer ctk_action_helper_parent_class = ((void*)0); static
gint CtkActionHelper_private_offset; static void ctk_action_helper_class_intern_init
(gpointer klass) { ctk_action_helper_parent_class = g_type_class_peek_parent
(klass); if (CtkActionHelper_private_offset != 0) g_type_class_adjust_private_offset
(klass, &CtkActionHelper_private_offset); ctk_action_helper_class_init
((CtkActionHelperClass*) klass); } __attribute__ ((__unused__
)) static inline gpointer ctk_action_helper_get_instance_private
(CtkActionHelper *self) { return (((gpointer) ((guint8*) (self
) + (glong) (CtkActionHelper_private_offset)))); } GType ctk_action_helper_get_type
(void) { static GType static_g_define_type_id = 0; if ((__extension__
({ _Static_assert (sizeof *(&static_g_define_type_id) ==
sizeof (gpointer), "Expression evaluates to false"); (void) (
0 ? (gpointer) * (&static_g_define_type_id) : ((void*)0))
; (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(*(&static_g_define_type_id)) gapg_temp_newval; __typeof__
((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id
); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5)
; gapg_temp_newval; })) && g_once_init_enter_pointer (
&static_g_define_type_id)); })) ) { GType g_define_type_id
= ctk_action_helper_get_type_once (); (__extension__ ({ _Static_assert
(sizeof *(&static_g_define_type_id) == sizeof (gpointer)
, "Expression evaluates to false"); 0 ? (void) (*(&static_g_define_type_id
) = (g_define_type_id)) : (void) 0; g_once_init_leave_pointer
((&static_g_define_type_id), (gpointer) (guintptr) (g_define_type_id
)); })) ; } return static_g_define_type_id; } __attribute__ (
(__noinline__)) static GType ctk_action_helper_get_type_once (
void) { GType g_define_type_id = g_type_register_static_simple
(((GType) ((20) << (2))), g_intern_static_string ("CtkActionHelper"
), sizeof (CtkActionHelperClass), (GClassInitFunc)(void (*)(void
)) ctk_action_helper_class_intern_init, sizeof (CtkActionHelper
), (GInstanceInitFunc)(void (*)(void)) ctk_action_helper_init
, (GTypeFlags) 0); { {{ const GInterfaceInfo g_implement_interface_info
= { (GInterfaceInitFunc)(void (*)(void)) ctk_action_helper_observer_iface_init
, ((void*)0), ((void*)0) }; g_type_add_interface_static (g_define_type_id
, (ctk_action_observer_get_type ()), &g_implement_interface_info
); };} } return g_define_type_id; }
91 G_IMPLEMENT_INTERFACE (CTK_TYPE_ACTION_OBSERVER, ctk_action_helper_observer_iface_init))static void ctk_action_helper_init (CtkActionHelper *self); static
void ctk_action_helper_class_init (CtkActionHelperClass *klass
); static GType ctk_action_helper_get_type_once (void); static
gpointer ctk_action_helper_parent_class = ((void*)0); static
gint CtkActionHelper_private_offset; static void ctk_action_helper_class_intern_init
(gpointer klass) { ctk_action_helper_parent_class = g_type_class_peek_parent
(klass); if (CtkActionHelper_private_offset != 0) g_type_class_adjust_private_offset
(klass, &CtkActionHelper_private_offset); ctk_action_helper_class_init
((CtkActionHelperClass*) klass); } __attribute__ ((__unused__
)) static inline gpointer ctk_action_helper_get_instance_private
(CtkActionHelper *self) { return (((gpointer) ((guint8*) (self
) + (glong) (CtkActionHelper_private_offset)))); } GType ctk_action_helper_get_type
(void) { static GType static_g_define_type_id = 0; if ((__extension__
({ _Static_assert (sizeof *(&static_g_define_type_id) ==
sizeof (gpointer), "Expression evaluates to false"); (void) (
0 ? (gpointer) * (&static_g_define_type_id) : ((void*)0))
; (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(*(&static_g_define_type_id)) gapg_temp_newval; __typeof__
((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id
); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5)
; gapg_temp_newval; })) && g_once_init_enter_pointer (
&static_g_define_type_id)); })) ) { GType g_define_type_id
= ctk_action_helper_get_type_once (); (__extension__ ({ _Static_assert
(sizeof *(&static_g_define_type_id) == sizeof (gpointer)
, "Expression evaluates to false"); 0 ? (void) (*(&static_g_define_type_id
) = (g_define_type_id)) : (void) 0; g_once_init_leave_pointer
((&static_g_define_type_id), (gpointer) (guintptr) (g_define_type_id
)); })) ; } return static_g_define_type_id; } __attribute__ (
(__noinline__)) static GType ctk_action_helper_get_type_once (
void) { GType g_define_type_id = g_type_register_static_simple
(((GType) ((20) << (2))), g_intern_static_string ("CtkActionHelper"
), sizeof (CtkActionHelperClass), (GClassInitFunc)(void (*)(void
)) ctk_action_helper_class_intern_init, sizeof (CtkActionHelper
), (GInstanceInitFunc)(void (*)(void)) ctk_action_helper_init
, (GTypeFlags) 0); { {{ const GInterfaceInfo g_implement_interface_info
= { (GInterfaceInitFunc)(void (*)(void)) ctk_action_helper_observer_iface_init
, ((void*)0), ((void*)0) }; g_type_add_interface_static (g_define_type_id
, (ctk_action_observer_get_type ()), &g_implement_interface_info
); };} } return g_define_type_id; }
92
93static void
94ctk_action_helper_report_change (CtkActionHelper *helper,
95 guint prop_id)
96{
97 helper->reporting++;
98
99 switch (prop_id)
100 {
101 case PROP_ENABLED:
102 ctk_widget_set_sensitive (CTK_WIDGET (helper->widget)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((helper->widget)), ((ctk_widget_get_type ()))))))
, helper->enabled);
103 break;
104
105 case PROP_ACTIVE:
106 {
107 GParamSpec *pspec;
108
109 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (helper->widget)((((GObjectClass*) (((GTypeInstance*) ((helper->widget)))->
g_class))))
, "active");
110
111 if (pspec && G_PARAM_SPEC_VALUE_TYPE (pspec)(((((GParamSpec*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((pspec)), (((GType) ((19) << (2))))))))->value_type
)
== G_TYPE_BOOLEAN((GType) ((5) << (2))))
112 g_object_set (G_OBJECT (helper->widget)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((helper->widget)), (((GType) ((20) << (2))))))))
, "active", helper->active, NULL((void*)0));
113 }
114 break;
115
116 case PROP_ROLE:
117 {
118 GParamSpec *pspec;
119
120 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (helper->widget)((((GObjectClass*) (((GTypeInstance*) ((helper->widget)))->
g_class))))
, "role");
121
122 if (pspec && G_PARAM_SPEC_VALUE_TYPE (pspec)(((((GParamSpec*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((pspec)), (((GType) ((19) << (2))))))))->value_type
)
== CTK_TYPE_BUTTON_ROLE(ctk_button_role_get_type ()))
123 g_object_set (G_OBJECT (helper->widget)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((helper->widget)), (((GType) ((20) << (2))))))))
, "role", helper->role, NULL((void*)0));
124 }
125 break;
126
127 default:
128 g_assert_not_reached ()do { g_assertion_message_expr ("Ctk", "ctkactionhelper.c", 128
, ((const char*) (__func__)), ((void*)0)); } while (0)
;
129 }
130
131 g_object_notify_by_pspec (G_OBJECT (helper)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((helper)), (((GType) ((20) << (2))))))))
, ctk_action_helper_pspecs[prop_id]);
132 helper->reporting--;
133}
134
135static void
136ctk_action_helper_action_added (CtkActionHelper *helper,
137 gboolean enabled,
138 const GVariantType *parameter_type,
139 GVariant *state,
140 gboolean should_emit_signals)
141{
142 CTK_NOTE(ACTIONS, g_message("%s: action %s added", "actionhelper", helper->action_name))do { if ((ctk_get_debug_flags () & CTK_DEBUG_ACTIONS)) { g_message
("%s: action %s added", "actionhelper", helper->action_name
); }; } while (0)
;
143
144 /* we can only activate if we have the correct type of parameter */
145 helper->can_activate = (helper->target == NULL((void*)0) && parameter_type == NULL((void*)0)) ||
146 (helper->target != NULL((void*)0) && parameter_type != NULL((void*)0) &&
147 g_variant_is_of_type (helper->target, parameter_type));
148
149 if (!helper->can_activate)
150 {
151 g_warning ("%s: action %s can't be activated due to parameter type mismatch "
152 "(parameter type %s, target type %s)",
153 "actionhelper",
154 helper->action_name,
155 parameter_type ? g_variant_type_peek_string (parameter_type) : "NULL",
156 helper->target ? g_variant_get_type_string (helper->target) : "NULL");
157 return;
158 }
159
160 CTK_NOTE(ACTIONS, g_message ("%s: %s can be activated", "actionhelper", helper->action_name))do { if ((ctk_get_debug_flags () & CTK_DEBUG_ACTIONS)) { g_message
("%s: %s can be activated", "actionhelper", helper->action_name
); }; } while (0)
;
161
162 helper->enabled = enabled;
163
164 CTK_NOTE(ACTIONS, g_message ("%s: action %s is %s", "actionhelper", helper->action_name, enabled ? "enabled" : "disabled"))do { if ((ctk_get_debug_flags () & CTK_DEBUG_ACTIONS)) { g_message
("%s: action %s is %s", "actionhelper", helper->action_name
, enabled ? "enabled" : "disabled"); }; } while (0)
;
165
166 if (helper->target != NULL((void*)0) && state != NULL((void*)0))
167 {
168 helper->active = g_variant_equal (state, helper->target);
169 helper->role = CTK_BUTTON_ROLE_RADIO;
170 }
171 else if (state != NULL((void*)0) && g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN((const GVariantType *) "b")))
172 {
173 helper->active = g_variant_get_boolean (state);
174 helper->role = CTK_BUTTON_ROLE_CHECK;
175 }
176 else
177 {
178 helper->role = CTK_BUTTON_ROLE_NORMAL;
179 }
180
181 if (should_emit_signals)
182 {
183 if (helper->enabled)
184 ctk_action_helper_report_change (helper, PROP_ENABLED);
185
186 if (helper->active)
187 ctk_action_helper_report_change (helper, PROP_ACTIVE);
188
189 ctk_action_helper_report_change (helper, PROP_ROLE);
190 }
191}
192
193static void
194ctk_action_helper_action_removed (CtkActionHelper *helper,
195 gboolean should_emit_signals)
196{
197 CTK_NOTE(ACTIONS, g_message ("%s: action %s was removed", "actionhelper", helper->action_name))do { if ((ctk_get_debug_flags () & CTK_DEBUG_ACTIONS)) { g_message
("%s: action %s was removed", "actionhelper", helper->action_name
); }; } while (0)
;
198
199 if (!helper->can_activate)
200 return;
201
202 helper->can_activate = FALSE(0);
203
204 if (helper->enabled)
205 {
206 helper->enabled = FALSE(0);
207
208 if (should_emit_signals)
209 ctk_action_helper_report_change (helper, PROP_ENABLED);
210 }
211
212 if (helper->active)
213 {
214 helper->active = FALSE(0);
215
216 if (should_emit_signals)
217 ctk_action_helper_report_change (helper, PROP_ACTIVE);
218 }
219}
220
221static void
222ctk_action_helper_action_enabled_changed (CtkActionHelper *helper,
223 gboolean enabled)
224{
225 CTK_NOTE(ACTIONS, g_message ("%s: action %s: enabled changed to %d", "actionhelper", helper->action_name, enabled))do { if ((ctk_get_debug_flags () & CTK_DEBUG_ACTIONS)) { g_message
("%s: action %s: enabled changed to %d", "actionhelper", helper
->action_name, enabled); }; } while (0)
;
226
227 if (!helper->can_activate)
228 return;
229
230 if (helper->enabled == enabled)
231 return;
232
233 helper->enabled = enabled;
234 ctk_action_helper_report_change (helper, PROP_ENABLED);
235}
236
237static void
238ctk_action_helper_action_state_changed (CtkActionHelper *helper,
239 GVariant *new_state)
240{
241 gboolean was_active;
242
243 CTK_NOTE(ACTIONS, g_message ("%s: %s state changed", "actionhelper", helper->action_name))do { if ((ctk_get_debug_flags () & CTK_DEBUG_ACTIONS)) { g_message
("%s: %s state changed", "actionhelper", helper->action_name
); }; } while (0)
;
244
245 if (!helper->can_activate)
246 return;
247
248 was_active = helper->active;
249
250 if (helper->target)
251 helper->active = g_variant_equal (new_state, helper->target);
252
253 else if (g_variant_is_of_type (new_state, G_VARIANT_TYPE_BOOLEAN((const GVariantType *) "b")))
Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption
254 helper->active = g_variant_get_boolean (new_state);
255
256 else
257 helper->active = FALSE(0);
258
259 if (helper->active != was_active)
260 ctk_action_helper_report_change (helper, PROP_ACTIVE);
261}
262
263static void
264ctk_action_helper_get_property (GObject *object,
265 guint prop_id,
266 GValue *value,
267 GParamSpec *pspec G_GNUC_UNUSED__attribute__ ((__unused__)))
268{
269 CtkActionHelper *helper = CTK_ACTION_HELPER (object)((((CtkActionHelper*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((ctk_action_helper_get_type ()))))))
;
270
271 switch (prop_id)
272 {
273 case PROP_ENABLED:
274 g_value_set_boolean (value, helper->enabled);
275 break;
276
277 case PROP_ACTIVE:
278 g_value_set_boolean (value, helper->active);
279 break;
280
281 case PROP_ROLE:
282 g_value_set_enum (value, helper->role);
283 break;
284
285 default:
286 g_assert_not_reached ()do { g_assertion_message_expr ("Ctk", "ctkactionhelper.c", 286
, ((const char*) (__func__)), ((void*)0)); } while (0)
;
287 }
288}
289
290static void
291ctk_action_helper_finalize (GObject *object)
292{
293 CtkActionHelper *helper = CTK_ACTION_HELPER (object)((((CtkActionHelper*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((ctk_action_helper_get_type ()))))))
;
294
295 g_free (helper->action_name);
296
297 if (helper->target)
298 g_variant_unref (helper->target);
299
300 G_OBJECT_CLASS (ctk_action_helper_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ctk_action_helper_parent_class)), (((GType) ((20) <<
(2))))))))
301 ->finalize (object);
302}
303
304static void
305ctk_action_helper_observer_action_added (CtkActionObserver *observer,
306 CtkActionObservable *observable G_GNUC_UNUSED__attribute__ ((__unused__)),
307 const gchar *action_name G_GNUC_UNUSED__attribute__ ((__unused__)),
308 const GVariantType *parameter_type,
309 gboolean enabled,
310 GVariant *state)
311{
312 ctk_action_helper_action_added (CTK_ACTION_HELPER (observer)((((CtkActionHelper*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((observer)), ((ctk_action_helper_get_type ()))))))
, enabled, parameter_type, state, TRUE(!(0)));
313}
314
315static void
316ctk_action_helper_observer_action_enabled_changed (CtkActionObserver *observer,
317 CtkActionObservable *observable G_GNUC_UNUSED__attribute__ ((__unused__)),
318 const gchar *action_name G_GNUC_UNUSED__attribute__ ((__unused__)),
319 gboolean enabled)
320{
321 ctk_action_helper_action_enabled_changed (CTK_ACTION_HELPER (observer)((((CtkActionHelper*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((observer)), ((ctk_action_helper_get_type ()))))))
, enabled);
322}
323
324static void
325ctk_action_helper_observer_action_state_changed (CtkActionObserver *observer,
326 CtkActionObservable *observable G_GNUC_UNUSED__attribute__ ((__unused__)),
327 const gchar *action_name G_GNUC_UNUSED__attribute__ ((__unused__)),
328 GVariant *state)
329{
330 ctk_action_helper_action_state_changed (CTK_ACTION_HELPER (observer)((((CtkActionHelper*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((observer)), ((ctk_action_helper_get_type ()))))))
, state);
331}
332
333static void
334ctk_action_helper_observer_action_removed (CtkActionObserver *observer,
335 CtkActionObservable *observable G_GNUC_UNUSED__attribute__ ((__unused__)),
336 const gchar *action_name G_GNUC_UNUSED__attribute__ ((__unused__)))
337{
338 ctk_action_helper_action_removed (CTK_ACTION_HELPER (observer)((((CtkActionHelper*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((observer)), ((ctk_action_helper_get_type ()))))))
, TRUE(!(0)));
339}
340
341static void
342ctk_action_helper_init (CtkActionHelper *helper G_GNUC_UNUSED__attribute__ ((__unused__)))
343{
344}
345
346static void
347ctk_action_helper_class_init (CtkActionHelperClass *class)
348{
349 class->get_property = ctk_action_helper_get_property;
350 class->finalize = ctk_action_helper_finalize;
351
352 ctk_action_helper_pspecs[PROP_ENABLED] = g_param_spec_boolean ("enabled", "enabled", "enabled", FALSE(0),
353 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS(G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB
)
);
354 ctk_action_helper_pspecs[PROP_ACTIVE] = g_param_spec_boolean ("active", "active", "active", FALSE(0),
355 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS(G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB
)
);
356 ctk_action_helper_pspecs[PROP_ROLE] = g_param_spec_enum ("role", "role", "role",
357 CTK_TYPE_BUTTON_ROLE(ctk_button_role_get_type ()),
358 CTK_BUTTON_ROLE_NORMAL,
359 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS(G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB
)
);
360 g_object_class_install_properties (class, N_PROPS, ctk_action_helper_pspecs);
361}
362
363static void
364ctk_action_helper_observer_iface_init (CtkActionObserverInterface *iface)
365{
366 iface->action_added = ctk_action_helper_observer_action_added;
367 iface->action_enabled_changed = ctk_action_helper_observer_action_enabled_changed;
368 iface->action_state_changed = ctk_action_helper_observer_action_state_changed;
369 iface->action_removed = ctk_action_helper_observer_action_removed;
370}
371
372/*< private >
373 * ctk_action_helper_new:
374 * @widget: a #CtkWidget implementing #CtkActionable
375 *
376 * Creates a helper to track the state of a named action. This will
377 * usually be used by widgets implementing #CtkActionable.
378 *
379 * This helper class is usually used by @widget itself. In order to
380 * avoid reference cycles, the helper does not hold a reference on
381 * @widget, but will assume that it continues to exist for the duration
382 * of the life of the helper. If you are using the helper from outside
383 * of the widget, you should take a ref on @widget for each ref you hold
384 * on the helper.
385 *
386 * Returns: a new #CtkActionHelper
387 */
388CtkActionHelper *
389ctk_action_helper_new (CtkActionable *widget)
390{
391 CtkActionHelper *helper;
392 GParamSpec *pspec;
393
394 g_return_val_if_fail (CTK_IS_ACTIONABLE (widget), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((widget)); GType __t = ((ctk_actionable_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_ACTIONABLE (widget)"); return (((void*)0)); } } while
(0)
;
395 helper = g_object_new (CTK_TYPE_ACTION_HELPER(ctk_action_helper_get_type ()), NULL((void*)0));
396
397 helper->widget = CTK_WIDGET (widget)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_widget_get_type ()))))))
;
398 helper->enabled = ctk_widget_get_sensitive (CTK_WIDGET (helper->widget)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((helper->widget)), ((ctk_widget_get_type ()))))))
);
399
400 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (helper->widget)((((GObjectClass*) (((GTypeInstance*) ((helper->widget)))->
g_class))))
, "active");
401 if (pspec && G_PARAM_SPEC_VALUE_TYPE (pspec)(((((GParamSpec*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((pspec)), (((GType) ((19) << (2))))))))->value_type
)
== G_TYPE_BOOLEAN((GType) ((5) << (2))))
402 g_object_get (G_OBJECT (helper->widget)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((helper->widget)), (((GType) ((20) << (2))))))))
, "active", &helper->active, NULL((void*)0));
403
404 helper->action_context = _ctk_widget_get_action_muxer (CTK_WIDGET (widget)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_widget_get_type ()))))))
, TRUE(!(0)));
405
406 return helper;
407}
408
409void
410ctk_action_helper_set_action_name (CtkActionHelper *helper,
411 const gchar *action_name)
412{
413 gboolean was_enabled, was_active;
414 const GVariantType *parameter_type;
415 gboolean enabled;
416 GVariant *state;
417
418 if (g_strcmp0 (action_name, helper->action_name) == 0)
419 return;
420
421 CTK_NOTE(ACTIONS,do { if ((ctk_get_debug_flags () & CTK_DEBUG_ACTIONS)) { if
(action_name == ((void*)0) || !strchr (action_name, '.')) g_message
("%s: action name %s doesn't look like 'app.' or 'win.'; " "it is unlikely to work"
, "actionhelper", action_name); }; } while (0)
422 if (action_name == NULL || !strchr (action_name, '.'))do { if ((ctk_get_debug_flags () & CTK_DEBUG_ACTIONS)) { if
(action_name == ((void*)0) || !strchr (action_name, '.')) g_message
("%s: action name %s doesn't look like 'app.' or 'win.'; " "it is unlikely to work"
, "actionhelper", action_name); }; } while (0)
423 g_message ("%s: action name %s doesn't look like 'app.' or 'win.'; "do { if ((ctk_get_debug_flags () & CTK_DEBUG_ACTIONS)) { if
(action_name == ((void*)0) || !strchr (action_name, '.')) g_message
("%s: action name %s doesn't look like 'app.' or 'win.'; " "it is unlikely to work"
, "actionhelper", action_name); }; } while (0)
424 "it is unlikely to work",do { if ((ctk_get_debug_flags () & CTK_DEBUG_ACTIONS)) { if
(action_name == ((void*)0) || !strchr (action_name, '.')) g_message
("%s: action name %s doesn't look like 'app.' or 'win.'; " "it is unlikely to work"
, "actionhelper", action_name); }; } while (0)
425 "actionhelper", action_name))do { if ((ctk_get_debug_flags () & CTK_DEBUG_ACTIONS)) { if
(action_name == ((void*)0) || !strchr (action_name, '.')) g_message
("%s: action name %s doesn't look like 'app.' or 'win.'; " "it is unlikely to work"
, "actionhelper", action_name); }; } while (0)
;
426
427 /* Start by recording the current state of our properties so we know
428 * what notify signals we will need to send.
429 */
430 was_enabled = helper->enabled;
431 was_active = helper->active;
432
433 if (helper->action_name)
434 {
435 ctk_action_helper_action_removed (helper, FALSE(0));
436 ctk_action_observable_unregister_observer (CTK_ACTION_OBSERVABLE (helper->action_context)((((CtkActionObservable*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((helper->action_context)), ((ctk_action_observable_get_type
()))))))
,
437 helper->action_name,
438 CTK_ACTION_OBSERVER (helper)((((CtkActionObserver*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((helper)), ((ctk_action_observer_get_type (
)))))))
);
439 g_clear_pointer (&helper->action_name, g_free)do { _Static_assert (sizeof *(&helper->action_name) ==
sizeof (gpointer), "Expression evaluates to false"); __typeof__
((&helper->action_name)) _pp = (&helper->action_name
); __typeof__ (*(&helper->action_name)) _ptr = *_pp; *
_pp = ((void*)0); if (_ptr) (g_free) (_ptr); } while (0)
;
440 }
441
442 if (action_name)
443 {
444 helper->action_name = g_strdup (action_name)g_strdup_inline (action_name);
445
446 ctk_action_observable_register_observer (CTK_ACTION_OBSERVABLE (helper->action_context)((((CtkActionObservable*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((helper->action_context)), ((ctk_action_observable_get_type
()))))))
,
447 helper->action_name,
448 CTK_ACTION_OBSERVER (helper)((((CtkActionObserver*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((helper)), ((ctk_action_observer_get_type (
)))))))
);
449
450 if (g_action_group_query_action (G_ACTION_GROUP (helper->action_context)((((GActionGroup*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((helper->action_context)), ((g_action_group_get_type (
)))))))
, helper->action_name,
451 &enabled, &parameter_type, NULL((void*)0), NULL((void*)0), &state))
452 {
453 CTK_NOTE(ACTIONS, g_message ("%s: action %s existed from the start", "actionhelper", helper->action_name))do { if ((ctk_get_debug_flags () & CTK_DEBUG_ACTIONS)) { g_message
("%s: action %s existed from the start", "actionhelper", helper
->action_name); }; } while (0)
;
454
455 ctk_action_helper_action_added (helper, enabled, parameter_type, state, FALSE(0));
456
457 if (state)
458 g_variant_unref (state);
459 }
460 else
461 {
462 CTK_NOTE(ACTIONS, g_message ("%s: action %s missing from the start", "actionhelper", helper->action_name))do { if ((ctk_get_debug_flags () & CTK_DEBUG_ACTIONS)) { g_message
("%s: action %s missing from the start", "actionhelper", helper
->action_name); }; } while (0)
;
463 helper->enabled = FALSE(0);
464 }
465 }
466
467 /* Send the notifies for the properties that changed.
468 *
469 * When called during construction, widget is NULL. We don't need to
470 * report in that case.
471 */
472 if (helper->enabled != was_enabled)
473 ctk_action_helper_report_change (helper, PROP_ENABLED);
474
475 if (helper->active != was_active)
476 ctk_action_helper_report_change (helper, PROP_ACTIVE);
477
478 g_object_notify (G_OBJECT (helper->widget)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((helper->widget)), (((GType) ((20) << (2))))))))
, "action-name");
479}
480
481/*< private >
482 * ctk_action_helper_set_action_target_value:
483 * @helper: a #CtkActionHelper
484 * @target_value: an action target, as per #CtkActionable
485 *
486 * This function consumes @action_target if it is floating.
487 */
488void
489ctk_action_helper_set_action_target_value (CtkActionHelper *helper,
490 GVariant *target_value)
491{
492 gboolean was_enabled;
493 gboolean was_active;
494
495 if (target_value == helper->target)
496 return;
497
498 if (target_value && helper->target && g_variant_equal (target_value, helper->target))
499 {
500 g_variant_unref (g_variant_ref_sink (target_value));
501 return;
502 }
503
504 if (helper->target)
505 {
506 g_variant_unref (helper->target);
507 helper->target = NULL((void*)0);
508 }
509
510 if (target_value)
511 helper->target = g_variant_ref_sink (target_value);
512
513 /* The action_name has not yet been set. Don't do anything yet. */
514 if (helper->action_name == NULL((void*)0))
515 return;
516
517 was_enabled = helper->enabled;
518 was_active = helper->active;
519
520 /* If we are attached to an action group then it is possible that this
521 * change of the target value could impact our properties (including
522 * changes to 'can_activate' and therefore 'enabled', due to resolving
523 * a parameter type mismatch).
524 *
525 * Start over again by pretending the action gets re-added.
526 */
527 helper->can_activate = FALSE(0);
528 helper->enabled = FALSE(0);
529 helper->active = FALSE(0);
530
531 if (helper->action_context)
532 {
533 const GVariantType *parameter_type;
534 gboolean enabled;
535 GVariant *state;
536
537 if (g_action_group_query_action (G_ACTION_GROUP (helper->action_context)((((GActionGroup*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((helper->action_context)), ((g_action_group_get_type (
)))))))
,
538 helper->action_name, &enabled, &parameter_type,
539 NULL((void*)0), NULL((void*)0), &state))
540 {
541 ctk_action_helper_action_added (helper, enabled, parameter_type, state, FALSE(0));
542
543 if (state)
544 g_variant_unref (state);
545 }
546 }
547
548 if (helper->enabled != was_enabled)
549 ctk_action_helper_report_change (helper, PROP_ENABLED);
550
551 if (helper->active != was_active)
552 ctk_action_helper_report_change (helper, PROP_ACTIVE);
553
554 g_object_notify (G_OBJECT (helper->widget)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((helper->widget)), (((GType) ((20) << (2))))))))
, "action-target");
555}
556
557const gchar *
558ctk_action_helper_get_action_name (CtkActionHelper *helper)
559{
560 if (helper == NULL((void*)0))
561 return NULL((void*)0);
562
563 return helper->action_name;
564}
565
566GVariant *
567ctk_action_helper_get_action_target_value (CtkActionHelper *helper)
568{
569 if (helper == NULL((void*)0))
570 return NULL((void*)0);
571
572 return helper->target;
573}
574
575gboolean
576ctk_action_helper_get_enabled (CtkActionHelper *helper)
577{
578 g_return_val_if_fail (CTK_IS_ACTION_HELPER (helper), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((helper)); GType __t = ((ctk_action_helper_get_type ()));
gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
)))))) { } else { g_return_if_fail_warning ("Ctk", ((const char
*) (__func__)), "CTK_IS_ACTION_HELPER (helper)"); return ((0)
); } } while (0)
;
579
580 return helper->enabled;
581}
582
583gboolean
584ctk_action_helper_get_active (CtkActionHelper *helper)
585{
586 g_return_val_if_fail (CTK_IS_ACTION_HELPER (helper), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((helper)); GType __t = ((ctk_action_helper_get_type ()));
gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
)))))) { } else { g_return_if_fail_warning ("Ctk", ((const char
*) (__func__)), "CTK_IS_ACTION_HELPER (helper)"); return ((0)
); } } while (0)
;
587
588 return helper->active;
589}
590
591void
592ctk_action_helper_activate (CtkActionHelper *helper)
593{
594 g_return_if_fail (CTK_IS_ACTION_HELPER (helper))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((helper)); GType __t = ((ctk_action_helper_get_type ()));
gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
)))))) { } else { g_return_if_fail_warning ("Ctk", ((const char
*) (__func__)), "CTK_IS_ACTION_HELPER (helper)"); return; } }
while (0)
;
595
596 if (!helper->can_activate || helper->reporting)
597 return;
598
599 g_action_group_activate_action (G_ACTION_GROUP (helper->action_context)((((GActionGroup*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((helper->action_context)), ((g_action_group_get_type (
)))))))
,
600 helper->action_name, helper->target);
601}