Bug Summary

File:ctk/ctkactiongroup.c
Warning:line 482, column 14
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 ctkactiongroup.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-170505-43637-1 -x c ctkactiongroup.c
1/*
2 * CTK - The GIMP Toolkit
3 * Copyright (C) 1998, 1999 Red Hat, Inc.
4 * All rights reserved.
5 *
6 * This Library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
10 *
11 * This Library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20/*
21 * Author: James Henstridge <james@daa.com.au>
22 *
23 * Modified by the CTK+ Team and others 2003. See the AUTHORS
24 * file for a list of people on the CTK+ Team. See the ChangeLog
25 * files for a list of changes. These files are distributed with
26 * CTK+ at ftp://ftp.ctk.org/pub/ctk/.
27 */
28
29/**
30 * SECTION:ctkactiongroup
31 * @Short_description: A group of actions
32 * @Title: CtkActionGroup
33 *
34 * Actions are organised into groups. An action group is essentially a
35 * map from names to #CtkAction objects.
36 *
37 * All actions that would make sense to use in a particular context
38 * should be in a single group. Multiple action groups may be used for a
39 * particular user interface. In fact, it is expected that most nontrivial
40 * applications will make use of multiple groups. For example, in an
41 * application that can edit multiple documents, one group holding global
42 * actions (e.g. quit, about, new), and one group per document holding
43 * actions that act on that document (eg. save, cut/copy/paste, etc). Each
44 * window’s menus would be constructed from a combination of two action
45 * groups.
46 *
47 * ## Accelerators ## {#Action-Accel}
48 *
49 * Accelerators are handled by the CTK+ accelerator map. All actions are
50 * assigned an accelerator path (which normally has the form
51 * `<Actions>/group-name/action-name`) and a shortcut is associated with
52 * this accelerator path. All menuitems and toolitems take on this accelerator
53 * path. The CTK+ accelerator map code makes sure that the correct shortcut
54 * is displayed next to the menu item.
55 *
56 * # CtkActionGroup as CtkBuildable # {#CtkActionGroup-BUILDER-UI}
57 *
58 * The #CtkActionGroup implementation of the #CtkBuildable interface accepts
59 * #CtkAction objects as <child> elements in UI definitions.
60 *
61 * Note that it is probably more common to define actions and action groups
62 * in the code, since they are directly related to what the code can do.
63 *
64 * The CtkActionGroup implementation of the CtkBuildable interface supports
65 * a custom <accelerator> element, which has attributes named “key“ and
66 * “modifiers“ and allows to specify accelerators. This is similar to the
67 * <accelerator> element of #CtkWidget, the main difference is that
68 * it doesn’t allow you to specify a signal.
69 *
70 * ## A #CtkDialog UI definition fragment. ##
71 * |[
72 * <object class="CtkActionGroup" id="actiongroup">
73 * <child>
74 * <object class="CtkAction" id="About">
75 * <property name="name">About</property>
76 * <property name="stock_id">ctk-about</property>
77 * <signal handler="about_activate" name="activate"/>
78 * </object>
79 * <accelerator key="F1" modifiers="CDK_CONTROL_MASK | CDK_SHIFT_MASK"/>
80 * </child>
81 * </object>
82 * ]|
83 *
84 */
85
86#include "config.h"
87#include <string.h>
88
89#include "ctkactiongroup.h"
90#include "ctkbuildable.h"
91#include "ctkiconfactory.h"
92#include "ctkicontheme.h"
93#include "ctkstock.h"
94#include "ctktoggleaction.h"
95#include "ctkradioaction.h"
96#include "ctkaccelmap.h"
97#include "ctkmarshalers.h"
98#include "ctkbuilderprivate.h"
99#include "ctkprivate.h"
100#include "ctkintl.h"
101
102
103struct _CtkActionGroupPrivate
104{
105 gchar *name;
106 gboolean sensitive;
107 gboolean visible;
108 GHashTable *actions;
109 CtkAccelGroup *accel_group;
110
111 CtkTranslateFunc translate_func;
112 gpointer translate_data;
113 GDestroyNotify translate_notify;
114};
115
116enum
117{
118 CONNECT_PROXY,
119 DISCONNECT_PROXY,
120 PRE_ACTIVATE,
121 POST_ACTIVATE,
122 LAST_SIGNAL
123};
124
125enum
126{
127 PROP_0,
128 PROP_NAME,
129 PROP_SENSITIVE,
130 PROP_VISIBLE,
131 PROP_ACCEL_GROUP
132};
133
134static void ctk_action_group_init (CtkActionGroup *self);
135static void ctk_action_group_class_init (CtkActionGroupClass *class);
136static void ctk_action_group_finalize (GObject *object);
137static void ctk_action_group_set_property (GObject *object,
138 guint prop_id,
139 const GValue *value,
140 GParamSpec *pspec);
141static void ctk_action_group_get_property (GObject *object,
142 guint prop_id,
143 GValue *value,
144 GParamSpec *pspec);
145static CtkAction *ctk_action_group_real_get_action (CtkActionGroup *self,
146 const gchar *name);
147
148/* CtkBuildable */
149static void ctk_action_group_buildable_init (CtkBuildableIface *iface);
150static void ctk_action_group_buildable_add_child (CtkBuildable *buildable,
151 CtkBuilder *builder,
152 GObject *child,
153 const gchar *type);
154static void ctk_action_group_buildable_set_name (CtkBuildable *buildable,
155 const gchar *name);
156static const gchar* ctk_action_group_buildable_get_name (CtkBuildable *buildable);
157static gboolean ctk_action_group_buildable_custom_tag_start (CtkBuildable *buildable,
158 CtkBuilder *builder,
159 GObject *child,
160 const gchar *tagname,
161 GMarkupParser *parser,
162 gpointer *data);
163static void ctk_action_group_buildable_custom_tag_end (CtkBuildable *buildable,
164 CtkBuilder *builder,
165 GObject *child,
166 const gchar *tagname,
167 gpointer *user_data);
168
169static guint action_group_signals[LAST_SIGNAL] = { 0 };
170
171G_DEFINE_TYPE_WITH_CODE (CtkActionGroup, ctk_action_group, G_TYPE_OBJECT,static void ctk_action_group_init (CtkActionGroup *self); static
void ctk_action_group_class_init (CtkActionGroupClass *klass
); static GType ctk_action_group_get_type_once (void); static
gpointer ctk_action_group_parent_class = ((void*)0); static gint
CtkActionGroup_private_offset; static void ctk_action_group_class_intern_init
(gpointer klass) { ctk_action_group_parent_class = g_type_class_peek_parent
(klass); if (CtkActionGroup_private_offset != 0) g_type_class_adjust_private_offset
(klass, &CtkActionGroup_private_offset); ctk_action_group_class_init
((CtkActionGroupClass*) klass); } __attribute__ ((__unused__
)) static inline gpointer ctk_action_group_get_instance_private
(CtkActionGroup *self) { return (((gpointer) ((guint8*) (self
) + (glong) (CtkActionGroup_private_offset)))); } GType ctk_action_group_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_group_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_group_get_type_once (
void) { GType g_define_type_id = g_type_register_static_simple
(((GType) ((20) << (2))), g_intern_static_string ("CtkActionGroup"
), sizeof (CtkActionGroupClass), (GClassInitFunc)(void (*)(void
)) ctk_action_group_class_intern_init, sizeof (CtkActionGroup
), (GInstanceInitFunc)(void (*)(void)) ctk_action_group_init,
(GTypeFlags) 0); { {{ CtkActionGroup_private_offset = g_type_add_instance_private
(g_define_type_id, sizeof (CtkActionGroupPrivate)); } { const
GInterfaceInfo g_implement_interface_info = { (GInterfaceInitFunc
)(void (*)(void)) ctk_action_group_buildable_init, ((void*)0)
, ((void*)0) }; g_type_add_interface_static (g_define_type_id
, (ctk_buildable_get_type ()), &g_implement_interface_info
); };} } return g_define_type_id; }
172 G_ADD_PRIVATE (CtkActionGroup)static void ctk_action_group_init (CtkActionGroup *self); static
void ctk_action_group_class_init (CtkActionGroupClass *klass
); static GType ctk_action_group_get_type_once (void); static
gpointer ctk_action_group_parent_class = ((void*)0); static gint
CtkActionGroup_private_offset; static void ctk_action_group_class_intern_init
(gpointer klass) { ctk_action_group_parent_class = g_type_class_peek_parent
(klass); if (CtkActionGroup_private_offset != 0) g_type_class_adjust_private_offset
(klass, &CtkActionGroup_private_offset); ctk_action_group_class_init
((CtkActionGroupClass*) klass); } __attribute__ ((__unused__
)) static inline gpointer ctk_action_group_get_instance_private
(CtkActionGroup *self) { return (((gpointer) ((guint8*) (self
) + (glong) (CtkActionGroup_private_offset)))); } GType ctk_action_group_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_group_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_group_get_type_once (
void) { GType g_define_type_id = g_type_register_static_simple
(((GType) ((20) << (2))), g_intern_static_string ("CtkActionGroup"
), sizeof (CtkActionGroupClass), (GClassInitFunc)(void (*)(void
)) ctk_action_group_class_intern_init, sizeof (CtkActionGroup
), (GInstanceInitFunc)(void (*)(void)) ctk_action_group_init,
(GTypeFlags) 0); { {{ CtkActionGroup_private_offset = g_type_add_instance_private
(g_define_type_id, sizeof (CtkActionGroupPrivate)); } { const
GInterfaceInfo g_implement_interface_info = { (GInterfaceInitFunc
)(void (*)(void)) ctk_action_group_buildable_init, ((void*)0)
, ((void*)0) }; g_type_add_interface_static (g_define_type_id
, (ctk_buildable_get_type ()), &g_implement_interface_info
); };} } return g_define_type_id; }
173 G_IMPLEMENT_INTERFACE (CTK_TYPE_BUILDABLE,static void ctk_action_group_init (CtkActionGroup *self); static
void ctk_action_group_class_init (CtkActionGroupClass *klass
); static GType ctk_action_group_get_type_once (void); static
gpointer ctk_action_group_parent_class = ((void*)0); static gint
CtkActionGroup_private_offset; static void ctk_action_group_class_intern_init
(gpointer klass) { ctk_action_group_parent_class = g_type_class_peek_parent
(klass); if (CtkActionGroup_private_offset != 0) g_type_class_adjust_private_offset
(klass, &CtkActionGroup_private_offset); ctk_action_group_class_init
((CtkActionGroupClass*) klass); } __attribute__ ((__unused__
)) static inline gpointer ctk_action_group_get_instance_private
(CtkActionGroup *self) { return (((gpointer) ((guint8*) (self
) + (glong) (CtkActionGroup_private_offset)))); } GType ctk_action_group_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_group_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_group_get_type_once (
void) { GType g_define_type_id = g_type_register_static_simple
(((GType) ((20) << (2))), g_intern_static_string ("CtkActionGroup"
), sizeof (CtkActionGroupClass), (GClassInitFunc)(void (*)(void
)) ctk_action_group_class_intern_init, sizeof (CtkActionGroup
), (GInstanceInitFunc)(void (*)(void)) ctk_action_group_init,
(GTypeFlags) 0); { {{ CtkActionGroup_private_offset = g_type_add_instance_private
(g_define_type_id, sizeof (CtkActionGroupPrivate)); } { const
GInterfaceInfo g_implement_interface_info = { (GInterfaceInitFunc
)(void (*)(void)) ctk_action_group_buildable_init, ((void*)0)
, ((void*)0) }; g_type_add_interface_static (g_define_type_id
, (ctk_buildable_get_type ()), &g_implement_interface_info
); };} } return g_define_type_id; }
174 ctk_action_group_buildable_init))static void ctk_action_group_init (CtkActionGroup *self); static
void ctk_action_group_class_init (CtkActionGroupClass *klass
); static GType ctk_action_group_get_type_once (void); static
gpointer ctk_action_group_parent_class = ((void*)0); static gint
CtkActionGroup_private_offset; static void ctk_action_group_class_intern_init
(gpointer klass) { ctk_action_group_parent_class = g_type_class_peek_parent
(klass); if (CtkActionGroup_private_offset != 0) g_type_class_adjust_private_offset
(klass, &CtkActionGroup_private_offset); ctk_action_group_class_init
((CtkActionGroupClass*) klass); } __attribute__ ((__unused__
)) static inline gpointer ctk_action_group_get_instance_private
(CtkActionGroup *self) { return (((gpointer) ((guint8*) (self
) + (glong) (CtkActionGroup_private_offset)))); } GType ctk_action_group_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_group_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_group_get_type_once (
void) { GType g_define_type_id = g_type_register_static_simple
(((GType) ((20) << (2))), g_intern_static_string ("CtkActionGroup"
), sizeof (CtkActionGroupClass), (GClassInitFunc)(void (*)(void
)) ctk_action_group_class_intern_init, sizeof (CtkActionGroup
), (GInstanceInitFunc)(void (*)(void)) ctk_action_group_init,
(GTypeFlags) 0); { {{ CtkActionGroup_private_offset = g_type_add_instance_private
(g_define_type_id, sizeof (CtkActionGroupPrivate)); } { const
GInterfaceInfo g_implement_interface_info = { (GInterfaceInitFunc
)(void (*)(void)) ctk_action_group_buildable_init, ((void*)0)
, ((void*)0) }; g_type_add_interface_static (g_define_type_id
, (ctk_buildable_get_type ()), &g_implement_interface_info
); };} } return g_define_type_id; }
175
176static void
177ctk_action_group_class_init (CtkActionGroupClass *klass)
178{
179 GObjectClass *gobject_class;
180
181 gobject_class = G_OBJECT_CLASS (klass)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((klass)), (((GType) ((20) << (2))))))))
;
182
183 gobject_class->finalize = ctk_action_group_finalize;
184 gobject_class->set_property = ctk_action_group_set_property;
185 gobject_class->get_property = ctk_action_group_get_property;
186 klass->get_action = ctk_action_group_real_get_action;
187
188 /**
189 * CtkActionGroup:name:
190 *
191 * A name for the action.
192 */
193 g_object_class_install_property (gobject_class,
194 PROP_NAME,
195 g_param_spec_string ("name",
196 P_("Name")g_dgettext("ctk30" "-properties","Name"),
197 P_("A name for the action group.")g_dgettext("ctk30" "-properties","A name for the action group."
)
,
198 NULL((void*)0),
199 CTK_PARAM_READWRITEG_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB | G_PARAM_CONSTRUCT_ONLY));
200 /**
201 * CtkActionGroup:sensitive:
202 *
203 * Whether the action group is enabled.
204 */
205 g_object_class_install_property (gobject_class,
206 PROP_SENSITIVE,
207 g_param_spec_boolean ("sensitive",
208 P_("Sensitive")g_dgettext("ctk30" "-properties","Sensitive"),
209 P_("Whether the action group is enabled.")g_dgettext("ctk30" "-properties","Whether the action group is enabled."
)
,
210 TRUE(!(0)),
211 CTK_PARAM_READWRITEG_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
212 /**
213 * CtkActionGroup:visible:
214 *
215 * Whether the action group is visible.
216 */
217 g_object_class_install_property (gobject_class,
218 PROP_VISIBLE,
219 g_param_spec_boolean ("visible",
220 P_("Visible")g_dgettext("ctk30" "-properties","Visible"),
221 P_("Whether the action group is visible.")g_dgettext("ctk30" "-properties","Whether the action group is visible."
)
,
222 TRUE(!(0)),
223 CTK_PARAM_READWRITEG_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
224 /**
225 * CtkActionGroup:accel-group:
226 *
227 * The accelerator group the actions of this group should use.
228 */
229 g_object_class_install_property (gobject_class,
230 PROP_ACCEL_GROUP,
231 g_param_spec_object ("accel-group",
232 P_("Accelerator Group")g_dgettext("ctk30" "-properties","Accelerator Group"),
233 P_("The accelerator group the actions of this group should use.")g_dgettext("ctk30" "-properties","The accelerator group the actions of this group should use."
)
,
234 CTK_TYPE_ACCEL_GROUP(ctk_accel_group_get_type ()),
235 CTK_PARAM_READWRITEG_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
236
237 /**
238 * CtkActionGroup::connect-proxy:
239 * @action_group: the group
240 * @action: the action
241 * @proxy: the proxy
242 *
243 * The ::connect-proxy signal is emitted after connecting a proxy to
244 * an action in the group. Note that the proxy may have been connected
245 * to a different action before.
246 *
247 * This is intended for simple customizations for which a custom action
248 * class would be too clumsy, e.g. showing tooltips for menuitems in the
249 * statusbar.
250 *
251 * #CtkUIManager proxies the signal and provides global notification
252 * just before any action is connected to a proxy, which is probably more
253 * convenient to use.
254 *
255 * Since: 2.4
256 */
257 action_group_signals[CONNECT_PROXY] =
258 g_signal_new (I_("connect-proxy")g_intern_static_string ("connect-proxy"),
259 G_OBJECT_CLASS_TYPE (klass)((((GTypeClass*) (klass))->g_type)),
260 0, 0, NULL((void*)0), NULL((void*)0),
261 _ctk_marshal_VOID__OBJECT_OBJECT,
262 G_TYPE_NONE((GType) ((1) << (2))), 2,
263 CTK_TYPE_ACTION(ctk_action_get_type ()), CTK_TYPE_WIDGET(ctk_widget_get_type ()));
264
265 /**
266 * CtkActionGroup::disconnect-proxy:
267 * @action_group: the group
268 * @action: the action
269 * @proxy: the proxy
270 *
271 * The ::disconnect-proxy signal is emitted after disconnecting a proxy
272 * from an action in the group.
273 *
274 * #CtkUIManager proxies the signal and provides global notification
275 * just before any action is connected to a proxy, which is probably more
276 * convenient to use.
277 *
278 * Since: 2.4
279 */
280 action_group_signals[DISCONNECT_PROXY] =
281 g_signal_new (I_("disconnect-proxy")g_intern_static_string ("disconnect-proxy"),
282 G_OBJECT_CLASS_TYPE (klass)((((GTypeClass*) (klass))->g_type)),
283 0, 0, NULL((void*)0), NULL((void*)0),
284 _ctk_marshal_VOID__OBJECT_OBJECT,
285 G_TYPE_NONE((GType) ((1) << (2))), 2,
286 CTK_TYPE_ACTION(ctk_action_get_type ()), CTK_TYPE_WIDGET(ctk_widget_get_type ()));
287
288 /**
289 * CtkActionGroup::pre-activate:
290 * @action_group: the group
291 * @action: the action
292 *
293 * The ::pre-activate signal is emitted just before the @action in the
294 * @action_group is activated
295 *
296 * This is intended for #CtkUIManager to proxy the signal and provide global
297 * notification just before any action is activated.
298 *
299 * Since: 2.4
300 */
301 action_group_signals[PRE_ACTIVATE] =
302 g_signal_new (I_("pre-activate")g_intern_static_string ("pre-activate"),
303 G_OBJECT_CLASS_TYPE (klass)((((GTypeClass*) (klass))->g_type)),
304 0, 0, NULL((void*)0), NULL((void*)0),
305 NULL((void*)0),
306 G_TYPE_NONE((GType) ((1) << (2))), 1,
307 CTK_TYPE_ACTION(ctk_action_get_type ()));
308
309 /**
310 * CtkActionGroup::post-activate:
311 * @action_group: the group
312 * @action: the action
313 *
314 * The ::post-activate signal is emitted just after the @action in the
315 * @action_group is activated
316 *
317 * This is intended for #CtkUIManager to proxy the signal and provide global
318 * notification just after any action is activated.
319 *
320 * Since: 2.4
321 */
322 action_group_signals[POST_ACTIVATE] =
323 g_signal_new (I_("post-activate")g_intern_static_string ("post-activate"),
324 G_OBJECT_CLASS_TYPE (klass)((((GTypeClass*) (klass))->g_type)),
325 0, 0, NULL((void*)0), NULL((void*)0),
326 NULL((void*)0),
327 G_TYPE_NONE((GType) ((1) << (2))), 1,
328 CTK_TYPE_ACTION(ctk_action_get_type ()));
329}
330
331
332static void
333remove_action (CtkAction *action)
334{
335 g_object_set (action, I_("action-group")g_intern_static_string ("action-group"), NULL((void*)0), NULL((void*)0));
336 g_object_unref (action);
337}
338
339static void
340ctk_action_group_init (CtkActionGroup *action_group)
341{
342 action_group->priv = ctk_action_group_get_instance_private (action_group);
343 action_group->priv->name = NULL((void*)0);
344 action_group->priv->sensitive = TRUE(!(0));
345 action_group->priv->visible = TRUE(!(0));
346 action_group->priv->actions = g_hash_table_new_full (g_str_hash, g_str_equal,
347 NULL((void*)0),
348 (GDestroyNotify) remove_action);
349 action_group->priv->translate_func = NULL((void*)0);
350 action_group->priv->translate_data = NULL((void*)0);
351 action_group->priv->translate_notify = NULL((void*)0);
352}
353
354static void
355ctk_action_group_buildable_init (CtkBuildableIface *iface)
356{
357 iface->add_child = ctk_action_group_buildable_add_child;
358 iface->set_name = ctk_action_group_buildable_set_name;
359 iface->get_name = ctk_action_group_buildable_get_name;
360 iface->custom_tag_start = ctk_action_group_buildable_custom_tag_start;
361 iface->custom_tag_end = ctk_action_group_buildable_custom_tag_end;
362}
363
364static void
365ctk_action_group_buildable_add_child (CtkBuildable *buildable,
366 CtkBuilder *builder G_GNUC_UNUSED__attribute__ ((__unused__)),
367 GObject *child,
368 const gchar *type G_GNUC_UNUSED__attribute__ ((__unused__)))
369{
370 ctk_action_group_add_action_with_accel (CTK_ACTION_GROUP (buildable)((((CtkActionGroup*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((buildable)), ((ctk_action_group_get_type ()))))))
,
371 CTK_ACTION (child)((((CtkAction*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_action_get_type ()))))))
, NULL((void*)0));
372}
373
374static void
375ctk_action_group_buildable_set_name (CtkBuildable *buildable,
376 const gchar *name)
377{
378 CtkActionGroup *self = CTK_ACTION_GROUP (buildable)((((CtkActionGroup*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((buildable)), ((ctk_action_group_get_type ()))))))
;
379 CtkActionGroupPrivate *private = self->priv;
380
381 private->name = g_strdup (name)g_strdup_inline (name);
382}
383
384static const gchar *
385ctk_action_group_buildable_get_name (CtkBuildable *buildable)
386{
387 CtkActionGroup *self = CTK_ACTION_GROUP (buildable)((((CtkActionGroup*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((buildable)), ((ctk_action_group_get_type ()))))))
;
388 CtkActionGroupPrivate *private = self->priv;
389
390 return private->name;
391}
392
393typedef struct {
394 GObject *child;
395 guint key;
396 CdkModifierType modifiers;
397} AcceleratorParserData;
398
399static void
400accelerator_start_element (GMarkupParseContext *context G_GNUC_UNUSED__attribute__ ((__unused__)),
401 const gchar *element_name,
402 const gchar **names,
403 const gchar **values,
404 gpointer user_data,
405 GError **error)
406{
407 gint i;
408 guint key = 0;
409 CdkModifierType modifiers = 0;
410 AcceleratorParserData *parser_data = (AcceleratorParserData*)user_data;
411
412 if (strcmp (element_name, "accelerator") != 0)
413 g_warning ("Unknown <accelerator> tag: %s", element_name);
414
415 for (i = 0; names[i]; i++)
416 {
417 if (strcmp (names[i], "key") == 0)
418 key = cdk_keyval_from_name (values[i]);
419 else if (strcmp (names[i], "modifiers") == 0)
420 {
421 if (!_ctk_builder_flags_from_string (CDK_TYPE_MODIFIER_TYPE(cdk_modifier_type_get_type ()),
422 NULL((void*)0),
423 values[i],
424 &modifiers,
425 error))
426 return;
427 }
428 }
429
430 if (key == 0)
431 {
432 g_warning ("<accelerator> requires a key attribute");
433 return;
434 }
435 parser_data->key = key;
436 parser_data->modifiers = modifiers;
437}
438
439static const GMarkupParser accelerator_parser =
440 {
441 .start_element = accelerator_start_element
442 };
443
444static gboolean
445ctk_action_group_buildable_custom_tag_start (CtkBuildable *buildable G_GNUC_UNUSED__attribute__ ((__unused__)),
446 CtkBuilder *builder G_GNUC_UNUSED__attribute__ ((__unused__)),
447 GObject *child,
448 const gchar *tagname,
449 GMarkupParser *parser,
450 gpointer *user_data)
451{
452 AcceleratorParserData *parser_data;
453
454 if (child && strcmp (tagname, "accelerator") == 0)
455 {
456 parser_data = g_slice_new0 (AcceleratorParserData)((AcceleratorParserData*) g_slice_alloc0 (sizeof (AcceleratorParserData
)))
;
457 parser_data->child = child;
458 *user_data = parser_data;
459 *parser = accelerator_parser;
460
461 return TRUE(!(0));
462 }
463 return FALSE(0);
464}
465
466static void
467ctk_action_group_buildable_custom_tag_end (CtkBuildable *buildable,
468 CtkBuilder *builder G_GNUC_UNUSED__attribute__ ((__unused__)),
469 GObject *child,
470 const gchar *tagname,
471 gpointer *user_data)
472{
473 AcceleratorParserData *data;
474
475 if (strcmp (tagname, "accelerator") == 0)
476 {
477 CtkActionGroup *action_group;
478 CtkActionGroupPrivate *private;
479 CtkAction *action;
480 gchar *accel_path;
481
482 data = (AcceleratorParserData*)user_data;
Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption
483 action_group = CTK_ACTION_GROUP (buildable)((((CtkActionGroup*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((buildable)), ((ctk_action_group_get_type ()))))))
;
484 private = action_group->priv;
485 action = CTK_ACTION (child)((((CtkAction*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_action_get_type ()))))))
;
486
487 accel_path = g_strconcat ("<Actions>/",
488 private->name, "/",
489 ctk_action_get_name (action), NULL((void*)0));
490
491 if (ctk_accel_map_lookup_entry (accel_path, NULL((void*)0)))
492 ctk_accel_map_change_entry (accel_path, data->key, data->modifiers, TRUE(!(0)));
493 else
494 ctk_accel_map_add_entry (accel_path, data->key, data->modifiers);
495
496 ctk_action_set_accel_path (action, accel_path);
497
498 g_free (accel_path);
499 g_slice_free (AcceleratorParserData, data)do { if (1) g_slice_free1 (sizeof (AcceleratorParserData), (data
)); else (void) ((AcceleratorParserData*) 0 == (data)); } while
(0)
;
500 }
501}
502
503/**
504 * ctk_action_group_new:
505 * @name: the name of the action group.
506 *
507 * Creates a new #CtkActionGroup object. The name of the action group
508 * is used when associating [keybindings][Action-Accel]
509 * with the actions.
510 *
511 * Returns: the new #CtkActionGroup
512 *
513 * Since: 2.4
514 */
515CtkActionGroup *
516ctk_action_group_new (const gchar *name)
517{
518 CtkActionGroup *self;
519 CtkActionGroupPrivate *private;
520
521 self = g_object_new (CTK_TYPE_ACTION_GROUP(ctk_action_group_get_type ()), NULL((void*)0));
522 private = self->priv;
523 private->name = g_strdup (name)g_strdup_inline (name);
524
525 return self;
526}
527
528static void
529ctk_action_group_finalize (GObject *object)
530{
531 CtkActionGroup *self = CTK_ACTION_GROUP (object)((((CtkActionGroup*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((ctk_action_group_get_type ()))))))
;
532
533 g_free (self->priv->name);
534
535 g_hash_table_destroy (self->priv->actions);
536
537 g_clear_object (&self->priv->accel_group)do { _Static_assert (sizeof *((&self->priv->accel_group
)) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&self->priv->accel_group))) _pp = ((&self->
priv->accel_group)); __typeof__ (*((&self->priv->
accel_group))) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (g_object_unref
) (_ptr); } while (0)
;
538
539 if (self->priv->translate_notify != NULL((void*)0))
540 self->priv->translate_notify (self->priv->translate_data);
541
542 G_OBJECT_CLASS (ctk_action_group_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ctk_action_group_parent_class)), (((GType) ((20) <<
(2))))))))
->finalize (object);
543}
544
545static void
546ctk_action_group_set_property (GObject *object,
547 guint prop_id,
548 const GValue *value,
549 GParamSpec *pspec)
550{
551 CtkActionGroup *self;
552 CtkActionGroupPrivate *private;
553 gchar *tmp;
554
555 self = CTK_ACTION_GROUP (object)((((CtkActionGroup*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((ctk_action_group_get_type ()))))))
;
556 private = self->priv;
557
558 switch (prop_id)
559 {
560 case PROP_NAME:
561 tmp = private->name;
562 private->name = g_value_dup_string (value);
563 g_free (tmp);
564 break;
565 case PROP_SENSITIVE:
566 ctk_action_group_set_sensitive (self, g_value_get_boolean (value));
567 break;
568 case PROP_VISIBLE:
569 ctk_action_group_set_visible (self, g_value_get_boolean (value));
570 break;
571 case PROP_ACCEL_GROUP:
572 ctk_action_group_set_accel_group (self, g_value_get_object (value));
573 break;
574 default:
575 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec)do { GObject *_glib__object = (GObject*) ((object)); GParamSpec
*_glib__pspec = (GParamSpec*) ((pspec)); guint _glib__property_id
= ((prop_id)); g_warning ("%s:%d: invalid %s id %u for \"%s\" of type '%s' in '%s'"
, "ctkactiongroup.c", 575, ("property"), _glib__property_id, _glib__pspec
->name, g_type_name ((((((GTypeClass*) (((GTypeInstance*) (
_glib__pspec))->g_class))->g_type)))), (g_type_name (((
(((GTypeClass*) (((GTypeInstance*) (_glib__object))->g_class
))->g_type)))))); } while (0)
;
576 break;
577 }
578}
579
580static void
581ctk_action_group_get_property (GObject *object,
582 guint prop_id,
583 GValue *value,
584 GParamSpec *pspec)
585{
586 CtkActionGroup *self;
587 CtkActionGroupPrivate *private;
588
589 self = CTK_ACTION_GROUP (object)((((CtkActionGroup*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((ctk_action_group_get_type ()))))))
;
590 private = self->priv;
591
592 switch (prop_id)
593 {
594 case PROP_NAME:
595 g_value_set_string (value, private->name);
596 break;
597 case PROP_SENSITIVE:
598 g_value_set_boolean (value, private->sensitive);
599 break;
600 case PROP_VISIBLE:
601 g_value_set_boolean (value, private->visible);
602 break;
603 case PROP_ACCEL_GROUP:
604 g_value_set_object (value, private->accel_group);
605 break;
606 default:
607 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec)do { GObject *_glib__object = (GObject*) ((object)); GParamSpec
*_glib__pspec = (GParamSpec*) ((pspec)); guint _glib__property_id
= ((prop_id)); g_warning ("%s:%d: invalid %s id %u for \"%s\" of type '%s' in '%s'"
, "ctkactiongroup.c", 607, ("property"), _glib__property_id, _glib__pspec
->name, g_type_name ((((((GTypeClass*) (((GTypeInstance*) (
_glib__pspec))->g_class))->g_type)))), (g_type_name (((
(((GTypeClass*) (((GTypeInstance*) (_glib__object))->g_class
))->g_type)))))); } while (0)
;
608 break;
609 }
610}
611
612static CtkAction *
613ctk_action_group_real_get_action (CtkActionGroup *self,
614 const gchar *action_name)
615{
616 CtkActionGroupPrivate *private;
617
618 private = self->priv;
619
620 return g_hash_table_lookup (private->actions, action_name);
621}
622
623/**
624 * ctk_action_group_get_name:
625 * @action_group: the action group
626 *
627 * Gets the name of the action group.
628 *
629 * Returns: the name of the action group.
630 *
631 * Since: 2.4
632 */
633const gchar *
634ctk_action_group_get_name (CtkActionGroup *action_group)
635{
636 CtkActionGroupPrivate *private;
637
638 g_return_val_if_fail (CTK_IS_ACTION_GROUP (action_group), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((action_group)); GType __t = ((ctk_action_group_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_GROUP (action_group)"); return
(((void*)0)); } } while (0)
;
639
640 private = action_group->priv;
641
642 return private->name;
643}
644
645/**
646 * ctk_action_group_get_sensitive:
647 * @action_group: the action group
648 *
649 * Returns %TRUE if the group is sensitive. The constituent actions
650 * can only be logically sensitive (see ctk_action_is_sensitive()) if
651 * they are sensitive (see ctk_action_get_sensitive()) and their group
652 * is sensitive.
653 *
654 * Returns: %TRUE if the group is sensitive.
655 *
656 * Since: 2.4
657 */
658gboolean
659ctk_action_group_get_sensitive (CtkActionGroup *action_group)
660{
661 CtkActionGroupPrivate *private;
662
663 g_return_val_if_fail (CTK_IS_ACTION_GROUP (action_group), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((action_group)); GType __t = ((ctk_action_group_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_GROUP (action_group)"); return
((0)); } } while (0)
;
664
665 private = action_group->priv;
666
667 return private->sensitive;
668}
669
670static void
671cb_set_action_sensitivity (const gchar *name G_GNUC_UNUSED__attribute__ ((__unused__)),
672 CtkAction *action)
673{
674 /* Minor optimization, the action_groups state only affects actions
675 * that are themselves sensitive */
676 g_object_notify (G_OBJECT (action)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action)), (((GType) ((20) << (2))))))))
, "sensitive");
677
678}
679
680/**
681 * ctk_action_group_set_sensitive:
682 * @action_group: the action group
683 * @sensitive: new sensitivity
684 *
685 * Changes the sensitivity of @action_group
686 *
687 * Since: 2.4
688 */
689void
690ctk_action_group_set_sensitive (CtkActionGroup *action_group,
691 gboolean sensitive)
692{
693 CtkActionGroupPrivate *private;
694
695 g_return_if_fail (CTK_IS_ACTION_GROUP (action_group))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((action_group)); GType __t = ((ctk_action_group_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_GROUP (action_group)"); return
; } } while (0)
;
696
697 private = action_group->priv;
698 sensitive = sensitive != FALSE(0);
699
700 if (private->sensitive != sensitive)
701 {
702 private->sensitive = sensitive;
703 g_hash_table_foreach (private->actions,
704 (GHFunc) cb_set_action_sensitivity, NULL((void*)0));
705
706 g_object_notify (G_OBJECT (action_group)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action_group)), (((GType) ((20) << (2))))))))
, "sensitive");
707 }
708}
709
710/**
711 * ctk_action_group_get_visible:
712 * @action_group: the action group
713 *
714 * Returns %TRUE if the group is visible. The constituent actions
715 * can only be logically visible (see ctk_action_is_visible()) if
716 * they are visible (see ctk_action_get_visible()) and their group
717 * is visible.
718 *
719 * Returns: %TRUE if the group is visible.
720 *
721 * Since: 2.4
722 */
723gboolean
724ctk_action_group_get_visible (CtkActionGroup *action_group)
725{
726 CtkActionGroupPrivate *private;
727
728 g_return_val_if_fail (CTK_IS_ACTION_GROUP (action_group), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((action_group)); GType __t = ((ctk_action_group_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_GROUP (action_group)"); return
((0)); } } while (0)
;
729
730 private = action_group->priv;
731
732 return private->visible;
733}
734
735/**
736 * ctk_action_group_get_accel_group:
737 * @action_group: a #CtkActionGroup
738 *
739 * Gets the accelerator group.
740 *
741 * Returns: (transfer none): the accelerator group associated with this action
742 * group or %NULL if there is none.
743 *
744 * Since: 3.6
745 */
746CtkAccelGroup *
747ctk_action_group_get_accel_group (CtkActionGroup *action_group)
748{
749 g_return_val_if_fail (CTK_IS_ACTION_GROUP (action_group), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((action_group)); GType __t = ((ctk_action_group_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_GROUP (action_group)"); return
((0)); } } while (0)
;
750
751 return action_group->priv->accel_group;
752}
753
754static void
755cb_set_action_visiblity (const gchar *name G_GNUC_UNUSED__attribute__ ((__unused__)),
756 CtkAction *action)
757{
758 /* Minor optimization, the action_groups state only affects actions
759 * that are themselves visible */
760 g_object_notify (G_OBJECT (action)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action)), (((GType) ((20) << (2))))))))
, "visible");
761}
762
763/**
764 * ctk_action_group_set_visible:
765 * @action_group: the action group
766 * @visible: new visiblity
767 *
768 * Changes the visible of @action_group.
769 *
770 * Since: 2.4
771 */
772void
773ctk_action_group_set_visible (CtkActionGroup *action_group,
774 gboolean visible)
775{
776 CtkActionGroupPrivate *private;
777
778 g_return_if_fail (CTK_IS_ACTION_GROUP (action_group))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((action_group)); GType __t = ((ctk_action_group_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_GROUP (action_group)"); return
; } } while (0)
;
779
780 private = action_group->priv;
781 visible = visible != FALSE(0);
782
783 if (private->visible != visible)
784 {
785 private->visible = visible;
786 g_hash_table_foreach (private->actions,
787 (GHFunc) cb_set_action_visiblity, NULL((void*)0));
788
789 g_object_notify (G_OBJECT (action_group)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action_group)), (((GType) ((20) << (2))))))))
, "visible");
790 }
791}
792
793static void
794ctk_action_group_accel_group_foreach (gpointer key G_GNUC_UNUSED__attribute__ ((__unused__)),
795 gpointer val,
796 gpointer data)
797{
798 ctk_action_set_accel_group (val, data);
799}
800
801/**
802 * ctk_action_group_set_accel_group:
803 * @action_group: a #CtkActionGroup
804 * @accel_group: (allow-none): a #CtkAccelGroup to set or %NULL
805 *
806 * Sets the accelerator group to be used by every action in this group.
807 *
808 * Since: 3.6
809 */
810void
811ctk_action_group_set_accel_group (CtkActionGroup *action_group,
812 CtkAccelGroup *accel_group)
813{
814 CtkActionGroupPrivate *private;
815
816 g_return_if_fail (CTK_IS_ACTION_GROUP (action_group))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((action_group)); GType __t = ((ctk_action_group_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_GROUP (action_group)"); return
; } } while (0)
;
817
818 private = action_group->priv;
819
820 if (private->accel_group == accel_group)
821 return;
822
823 g_clear_object (&private->accel_group)do { _Static_assert (sizeof *((&private->accel_group))
== sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&private->accel_group))) _pp = ((&private->
accel_group)); __typeof__ (*((&private->accel_group)))
_ptr = *_pp; *_pp = ((void*)0); if (_ptr) (g_object_unref) (
_ptr); } while (0)
;
824
825 if (accel_group)
826 private->accel_group = g_object_ref (accel_group)((__typeof__ (accel_group)) (g_object_ref) (accel_group));
827
828 /* Set the new accel group on every action */
829 g_hash_table_foreach (private->actions,
830 ctk_action_group_accel_group_foreach,
831 accel_group);
832
833 g_object_notify (G_OBJECT (action_group)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action_group)), (((GType) ((20) << (2))))))))
, "accel-group");
834}
835
836/**
837 * ctk_action_group_get_action:
838 * @action_group: the action group
839 * @action_name: the name of the action
840 *
841 * Looks up an action in the action group by name.
842 *
843 * Returns: (transfer none): the action, or %NULL if no action by that name exists
844 *
845 * Since: 2.4
846 */
847CtkAction *
848ctk_action_group_get_action (CtkActionGroup *action_group,
849 const gchar *action_name)
850{
851 g_return_val_if_fail (CTK_IS_ACTION_GROUP (action_group), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((action_group)); GType __t = ((ctk_action_group_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_GROUP (action_group)"); return
(((void*)0)); } } while (0)
;
852 g_return_val_if_fail (CTK_ACTION_GROUP_GET_CLASS (action_group)->get_action != NULL, NULL)do { if ((((((CtkActionGroupClass*) (((GTypeInstance*) ((action_group
)))->g_class))))->get_action != ((void*)0))) { } else {
g_return_if_fail_warning ("Ctk", ((const char*) (__func__)),
"CTK_ACTION_GROUP_GET_CLASS (action_group)->get_action != NULL"
); return (((void*)0)); } } while (0)
;
853
854 return CTK_ACTION_GROUP_GET_CLASS (action_group)((((CtkActionGroupClass*) (((GTypeInstance*) ((action_group))
)->g_class))))
->get_action (action_group,
855 action_name);
856}
857
858static gboolean
859check_unique_action (CtkActionGroup *action_group,
860 const gchar *action_name)
861{
862 if (ctk_action_group_get_action (action_group, action_name) != NULL((void*)0))
863 {
864 CtkActionGroupPrivate *private;
865
866 private = action_group->priv;
867
868 g_warning ("Refusing to add non-unique action '%s' to action group '%s'",
869 action_name,
870 private->name);
871 return FALSE(0);
872 }
873
874 return TRUE(!(0));
875}
876
877/**
878 * ctk_action_group_add_action:
879 * @action_group: the action group
880 * @action: an action
881 *
882 * Adds an action object to the action group. Note that this function
883 * does not set up the accel path of the action, which can lead to problems
884 * if a user tries to modify the accelerator of a menuitem associated with
885 * the action. Therefore you must either set the accel path yourself with
886 * ctk_action_set_accel_path(), or use
887 * `ctk_action_group_add_action_with_accel (..., NULL)`.
888 *
889 * Since: 2.4
890 */
891void
892ctk_action_group_add_action (CtkActionGroup *action_group,
893 CtkAction *action)
894{
895 CtkActionGroupPrivate *private;
896 const gchar *name;
897
898 g_return_if_fail (CTK_IS_ACTION_GROUP (action_group))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((action_group)); GType __t = ((ctk_action_group_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_GROUP (action_group)"); return
; } } while (0)
;
899 g_return_if_fail (CTK_IS_ACTION (action))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((action)); GType __t = ((ctk_action_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 (action)"); return; } } while (0)
;
900
901 name = ctk_action_get_name (action);
902 g_return_if_fail (name != NULL)do { if ((name != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "name != NULL"); return;
} } while (0)
;
903
904 if (!check_unique_action (action_group, name))
905 return;
906
907 private = action_group->priv;
908
909 g_hash_table_insert (private->actions,
910 (gpointer) name,
911 g_object_ref (action)((__typeof__ (action)) (g_object_ref) (action)));
912 g_object_set (action, I_("action-group")g_intern_static_string ("action-group"), action_group, NULL((void*)0));
913
914 if (private->accel_group)
915 ctk_action_set_accel_group (action, private->accel_group);
916}
917
918/**
919 * ctk_action_group_add_action_with_accel:
920 * @action_group: the action group
921 * @action: the action to add
922 * @accelerator: (allow-none): the accelerator for the action, in
923 * the format understood by ctk_accelerator_parse(), or "" for no accelerator, or
924 * %NULL to use the stock accelerator
925 *
926 * Adds an action object to the action group and sets up the accelerator.
927 *
928 * If @accelerator is %NULL, attempts to use the accelerator associated
929 * with the stock_id of the action.
930 *
931 * Accel paths are set to `<Actions>/group-name/action-name`.
932 *
933 * Since: 2.4
934 */
935void
936ctk_action_group_add_action_with_accel (CtkActionGroup *action_group,
937 CtkAction *action,
938 const gchar *accelerator)
939{
940 CtkActionGroupPrivate *private;
941 gchar *accel_path;
942 guint accel_key = 0;
943 CdkModifierType accel_mods;
944 const gchar *name;
945
946 name = ctk_action_get_name (action);
947 if (!check_unique_action (action_group, name))
948 return;
949
950 private = action_group->priv;
951 accel_path = g_strconcat ("<Actions>/",
952 private->name, "/", name, NULL((void*)0));
953
954 if (accelerator)
955 {
956 if (accelerator[0] == 0)
957 accel_key = 0;
958 else
959 {
960 ctk_accelerator_parse (accelerator, &accel_key, &accel_mods);
961 if (accel_key == 0)
962 g_warning ("Unable to parse accelerator '%s' for action '%s'",
963 accelerator, name);
964 }
965 }
966 else
967 {
968 gchar *stock_id;
969 CtkStockItem stock_item;
970
971 g_object_get (action, "stock-id", &stock_id, NULL((void*)0));
972
973 if (stock_id && ctk_stock_lookup (stock_id, &stock_item))
974 {
975 accel_key = stock_item.keyval;
976 accel_mods = stock_item.modifier;
977 }
978
979 g_free (stock_id);
980 }
981
982 if (accel_key)
983 ctk_accel_map_add_entry (accel_path, accel_key, accel_mods);
984
985 ctk_action_set_accel_path (action, accel_path);
986 ctk_action_group_add_action (action_group, action);
987
988 g_free (accel_path);
989}
990
991/**
992 * ctk_action_group_remove_action:
993 * @action_group: the action group
994 * @action: an action
995 *
996 * Removes an action object from the action group.
997 *
998 * Since: 2.4
999 */
1000void
1001ctk_action_group_remove_action (CtkActionGroup *action_group,
1002 CtkAction *action)
1003{
1004 CtkActionGroupPrivate *private;
1005 const gchar *name;
1006
1007 g_return_if_fail (CTK_IS_ACTION_GROUP (action_group))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((action_group)); GType __t = ((ctk_action_group_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_GROUP (action_group)"); return
; } } while (0)
;
1008 g_return_if_fail (CTK_IS_ACTION (action))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((action)); GType __t = ((ctk_action_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 (action)"); return; } } while (0)
;
1009
1010 name = ctk_action_get_name (action);
1011 g_return_if_fail (name != NULL)do { if ((name != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "name != NULL"); return;
} } while (0)
;
1012
1013 private = action_group->priv;
1014
1015 g_hash_table_remove (private->actions, name);
1016}
1017
1018static void
1019add_single_action (gpointer key G_GNUC_UNUSED__attribute__ ((__unused__)),
1020 gpointer value,
1021 gpointer user_data)
1022{
1023 GList **list = user_data;
1024
1025 *list = g_list_prepend (*list, value);
1026}
1027
1028/**
1029 * ctk_action_group_list_actions:
1030 * @action_group: the action group
1031 *
1032 * Lists the actions in the action group.
1033 *
1034 * Returns: (element-type CtkAction) (transfer container): an allocated list of the action objects in the action group
1035 *
1036 * Since: 2.4
1037 */
1038GList *
1039ctk_action_group_list_actions (CtkActionGroup *action_group)
1040{
1041 CtkActionGroupPrivate *private;
1042 GList *actions = NULL((void*)0);
1043
1044 g_return_val_if_fail (CTK_IS_ACTION_GROUP (action_group), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((action_group)); GType __t = ((ctk_action_group_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_GROUP (action_group)"); return
(((void*)0)); } } while (0)
;
1045
1046 private = action_group->priv;
1047
1048 g_hash_table_foreach (private->actions, add_single_action, &actions);
1049
1050 return g_list_reverse (actions);
1051}
1052
1053
1054/**
1055 * ctk_action_group_add_actions: (skip)
1056 * @action_group: the action group
1057 * @entries: (array length=n_entries): an array of action descriptions
1058 * @n_entries: the number of entries
1059 * @user_data: data to pass to the action callbacks
1060 *
1061 * This is a convenience function to create a number of actions and add them
1062 * to the action group.
1063 *
1064 * The “activate” signals of the actions are connected to the callbacks
1065 * and their accel paths are set to `<Actions>/group-name/action-name`.
1066 *
1067 * Since: 2.4
1068 */
1069void
1070ctk_action_group_add_actions (CtkActionGroup *action_group,
1071 const CtkActionEntry *entries,
1072 guint n_entries,
1073 gpointer user_data)
1074{
1075 ctk_action_group_add_actions_full (action_group,
1076 entries, n_entries,
1077 user_data, NULL((void*)0));
1078}
1079
1080typedef struct _SharedData SharedData;
1081
1082struct _SharedData {
1083 guint ref_count;
1084 gpointer data;
1085 GDestroyNotify destroy;
1086};
1087
1088static void
1089shared_data_unref (gpointer data)
1090{
1091 SharedData *shared_data = (SharedData *)data;
1092
1093 shared_data->ref_count--;
1094 if (shared_data->ref_count == 0)
1095 {
1096 if (shared_data->destroy)
1097 shared_data->destroy (shared_data->data);
1098
1099 g_slice_free (SharedData, shared_data)do { if (1) g_slice_free1 (sizeof (SharedData), (shared_data)
); else (void) ((SharedData*) 0 == (shared_data)); } while (0
)
;
1100 }
1101}
1102
1103
1104/**
1105 * ctk_action_group_add_actions_full: (skip)
1106 * @action_group: the action group
1107 * @entries: (array length=n_entries): an array of action descriptions
1108 * @n_entries: the number of entries
1109 * @user_data: data to pass to the action callbacks
1110 * @destroy: (nullable): destroy notification callback for @user_data
1111 *
1112 * This variant of ctk_action_group_add_actions() adds a #GDestroyNotify
1113 * callback for @user_data.
1114 *
1115 * Since: 2.4
1116 */
1117void
1118ctk_action_group_add_actions_full (CtkActionGroup *action_group,
1119 const CtkActionEntry *entries,
1120 guint n_entries,
1121 gpointer user_data,
1122 GDestroyNotify destroy)
1123{
1124
1125 /* Keep this in sync with the other
1126 * ctk_action_group_add_..._actions_full() functions.
1127 */
1128 guint i;
1129 SharedData *shared_data;
1130
1131 g_return_if_fail (CTK_IS_ACTION_GROUP (action_group))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((action_group)); GType __t = ((ctk_action_group_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_GROUP (action_group)"); return
; } } while (0)
;
1132
1133 shared_data = g_slice_new0 (SharedData)((SharedData*) g_slice_alloc0 (sizeof (SharedData)));
1134 shared_data->ref_count = 1;
1135 shared_data->data = user_data;
1136 shared_data->destroy = destroy;
1137
1138 for (i = 0; i < n_entries; i++)
1139 {
1140 CtkAction *action;
1141 const gchar *label;
1142 const gchar *tooltip;
1143
1144 if (!check_unique_action (action_group, entries[i].name))
1145 continue;
1146
1147 label = ctk_action_group_translate_string (action_group, entries[i].label);
1148 tooltip = ctk_action_group_translate_string (action_group, entries[i].tooltip);
1149
1150 action = ctk_action_new (entries[i].name,
1151 label,
1152 tooltip,
1153 NULL((void*)0));
1154
1155 if (entries[i].stock_id)
1156 {
1157 g_object_set (action, "stock-id", entries[i].stock_id, NULL((void*)0));
1158 if (ctk_icon_theme_has_icon (ctk_icon_theme_get_default (),
1159 entries[i].stock_id))
1160 g_object_set (action, "icon-name", entries[i].stock_id, NULL((void*)0));
1161 }
1162
1163 if (entries[i].callback)
1164 {
1165 GClosure *closure;
1166
1167 closure = g_cclosure_new (entries[i].callback, user_data, NULL((void*)0));
1168 g_closure_add_finalize_notifier (closure, shared_data,
1169 (GClosureNotify)shared_data_unref);
1170 shared_data->ref_count++;
1171
1172 g_signal_connect_closure (action, "activate", closure, FALSE(0));
1173 }
1174
1175 ctk_action_group_add_action_with_accel (action_group,
1176 action,
1177 entries[i].accelerator);
1178 g_object_unref (action);
1179 }
1180
1181 shared_data_unref (shared_data);
1182}
1183
1184/**
1185 * ctk_action_group_add_toggle_actions: (skip)
1186 * @action_group: the action group
1187 * @entries: (array length=n_entries): an array of toggle action descriptions
1188 * @n_entries: the number of entries
1189 * @user_data: data to pass to the action callbacks
1190 *
1191 * This is a convenience function to create a number of toggle actions and add them
1192 * to the action group.
1193 *
1194 * The “activate” signals of the actions are connected to the callbacks
1195 * and their accel paths are set to `<Actions>/group-name/action-name`.
1196 *
1197 * Since: 2.4
1198 */
1199void
1200ctk_action_group_add_toggle_actions (CtkActionGroup *action_group,
1201 const CtkToggleActionEntry *entries,
1202 guint n_entries,
1203 gpointer user_data)
1204{
1205 ctk_action_group_add_toggle_actions_full (action_group,
1206 entries, n_entries,
1207 user_data, NULL((void*)0));
1208}
1209
1210
1211/**
1212 * ctk_action_group_add_toggle_actions_full: (skip)
1213 * @action_group: the action group
1214 * @entries: (array length=n_entries): an array of toggle action descriptions
1215 * @n_entries: the number of entries
1216 * @user_data: data to pass to the action callbacks
1217 * @destroy: (nullable): destroy notification callback for @user_data
1218 *
1219 * This variant of ctk_action_group_add_toggle_actions() adds a
1220 * #GDestroyNotify callback for @user_data.
1221 *
1222 * Since: 2.4
1223 */
1224void
1225ctk_action_group_add_toggle_actions_full (CtkActionGroup *action_group,
1226 const CtkToggleActionEntry *entries,
1227 guint n_entries,
1228 gpointer user_data,
1229 GDestroyNotify destroy)
1230{
1231 /* Keep this in sync with the other
1232 * ctk_action_group_add_..._actions_full() functions.
1233 */
1234 guint i;
1235 SharedData *shared_data;
1236
1237 g_return_if_fail (CTK_IS_ACTION_GROUP (action_group))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((action_group)); GType __t = ((ctk_action_group_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_GROUP (action_group)"); return
; } } while (0)
;
1238
1239 shared_data = g_slice_new0 (SharedData)((SharedData*) g_slice_alloc0 (sizeof (SharedData)));
1240 shared_data->ref_count = 1;
1241 shared_data->data = user_data;
1242 shared_data->destroy = destroy;
1243
1244 for (i = 0; i < n_entries; i++)
1245 {
1246 CtkToggleAction *action;
1247 const gchar *label;
1248 const gchar *tooltip;
1249
1250 if (!check_unique_action (action_group, entries[i].name))
1251 continue;
1252
1253 label = ctk_action_group_translate_string (action_group, entries[i].label);
1254 tooltip = ctk_action_group_translate_string (action_group, entries[i].tooltip);
1255
1256 action = ctk_toggle_action_new (entries[i].name,
1257 label,
1258 tooltip,
1259 NULL((void*)0));
1260
1261 if (entries[i].stock_id)
1262 {
1263 if (ctk_icon_factory_lookup_default (entries[i].stock_id))
1264 g_object_set (action, "stock-id", entries[i].stock_id, NULL((void*)0));
1265 else
1266 g_object_set (action, "icon-name", entries[i].stock_id, NULL((void*)0));
1267 }
1268
1269 ctk_toggle_action_set_active (action, entries[i].is_active);
1270
1271 if (entries[i].callback)
1272 {
1273 GClosure *closure;
1274
1275 closure = g_cclosure_new (entries[i].callback, user_data, NULL((void*)0));
1276 g_closure_add_finalize_notifier (closure, shared_data,
1277 (GClosureNotify)shared_data_unref);
1278 shared_data->ref_count++;
1279
1280 g_signal_connect_closure (action, "activate", closure, FALSE(0));
1281 }
1282
1283 ctk_action_group_add_action_with_accel (action_group,
1284 CTK_ACTION (action)((((CtkAction*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action)), ((ctk_action_get_type ()))))))
,
1285 entries[i].accelerator);
1286 g_object_unref (action);
1287 }
1288
1289 shared_data_unref (shared_data);
1290}
1291
1292/**
1293 * ctk_action_group_add_radio_actions: (skip)
1294 * @action_group: the action group
1295 * @entries: (array length=n_entries): an array of radio action descriptions
1296 * @n_entries: the number of entries
1297 * @value: the value of the action to activate initially, or -1 if
1298 * no action should be activated
1299 * @on_change: the callback to connect to the changed signal
1300 * @user_data: data to pass to the action callbacks
1301 *
1302 * This is a convenience routine to create a group of radio actions and
1303 * add them to the action group.
1304 *
1305 * The “changed” signal of the first radio action is connected to the
1306 * @on_change callback and the accel paths of the actions are set to
1307 * `<Actions>/group-name/action-name`.
1308 *
1309 * Since: 2.4
1310 **/
1311void
1312ctk_action_group_add_radio_actions (CtkActionGroup *action_group,
1313 const CtkRadioActionEntry *entries,
1314 guint n_entries,
1315 gint value,
1316 GCallback on_change,
1317 gpointer user_data)
1318{
1319 ctk_action_group_add_radio_actions_full (action_group,
1320 entries, n_entries,
1321 value,
1322 on_change, user_data, NULL((void*)0));
1323}
1324
1325/**
1326 * ctk_action_group_add_radio_actions_full: (skip)
1327 * @action_group: the action group
1328 * @entries: (array length=n_entries): an array of radio action descriptions
1329 * @n_entries: the number of entries
1330 * @value: the value of the action to activate initially, or -1 if
1331 * no action should be activated
1332 * @on_change: the callback to connect to the changed signal
1333 * @user_data: data to pass to the action callbacks
1334 * @destroy: destroy notification callback for @user_data
1335 *
1336 * This variant of ctk_action_group_add_radio_actions() adds a
1337 * #GDestroyNotify callback for @user_data.
1338 *
1339 * Since: 2.4
1340 **/
1341void
1342ctk_action_group_add_radio_actions_full (CtkActionGroup *action_group,
1343 const CtkRadioActionEntry *entries,
1344 guint n_entries,
1345 gint value,
1346 GCallback on_change,
1347 gpointer user_data,
1348 GDestroyNotify destroy)
1349{
1350 /* Keep this in sync with the other
1351 * ctk_action_group_add_..._actions_full() functions.
1352 */
1353 guint i;
1354 GSList *group = NULL((void*)0);
1355 CtkRadioAction *first_action = NULL((void*)0);
1356
1357 g_return_if_fail (CTK_IS_ACTION_GROUP (action_group))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((action_group)); GType __t = ((ctk_action_group_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_GROUP (action_group)"); return
; } } while (0)
;
1358
1359 for (i = 0; i < n_entries; i++)
1360 {
1361 CtkRadioAction *action;
1362 const gchar *label;
1363 const gchar *tooltip;
1364
1365 if (!check_unique_action (action_group, entries[i].name))
1366 continue;
1367
1368 label = ctk_action_group_translate_string (action_group, entries[i].label);
1369 tooltip = ctk_action_group_translate_string (action_group, entries[i].tooltip);
1370
1371 action = ctk_radio_action_new (entries[i].name,
1372 label,
1373 tooltip,
1374 NULL((void*)0),
1375 entries[i].value);
1376
1377 if (entries[i].stock_id)
1378 {
1379 if (ctk_icon_factory_lookup_default (entries[i].stock_id))
1380 g_object_set (action, "stock-id", entries[i].stock_id, NULL((void*)0));
1381 else
1382 g_object_set (action, "icon-name", entries[i].stock_id, NULL((void*)0));
1383 }
1384
1385 if (i == 0)
1386 first_action = action;
1387
1388 ctk_radio_action_set_group (action, group);
1389 group = ctk_radio_action_get_group (action);
1390
1391 if (value == entries[i].value)
1392 ctk_toggle_action_set_active (CTK_TOGGLE_ACTION (action)((((CtkToggleAction*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action)), ((ctk_toggle_action_get_type ()))))))
, TRUE(!(0)));
1393
1394 ctk_action_group_add_action_with_accel (action_group,
1395 CTK_ACTION (action)((((CtkAction*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action)), ((ctk_action_get_type ()))))))
,
1396 entries[i].accelerator);
1397 g_object_unref (action);
1398 }
1399
1400 if (on_change && first_action)
1401 g_signal_connect_data (first_action, "changed",
1402 on_change, user_data,
1403 (GClosureNotify)destroy, 0);
1404}
1405
1406/**
1407 * ctk_action_group_set_translate_func:
1408 * @action_group: a #CtkActionGroup
1409 * @func: a #CtkTranslateFunc
1410 * @data: data to be passed to @func and @notify
1411 * @notify: a #GDestroyNotify function to be called when @action_group is
1412 * destroyed and when the translation function is changed again
1413 *
1414 * Sets a function to be used for translating the @label and @tooltip of
1415 * #CtkActionEntrys added by ctk_action_group_add_actions().
1416 *
1417 * If you’re using gettext(), it is enough to set the translation domain
1418 * with ctk_action_group_set_translation_domain().
1419 *
1420 * Since: 2.4
1421 **/
1422void
1423ctk_action_group_set_translate_func (CtkActionGroup *action_group,
1424 CtkTranslateFunc func,
1425 gpointer data,
1426 GDestroyNotify notify)
1427{
1428 CtkActionGroupPrivate *private;
1429
1430 g_return_if_fail (CTK_IS_ACTION_GROUP (action_group))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((action_group)); GType __t = ((ctk_action_group_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_GROUP (action_group)"); return
; } } while (0)
;
1431
1432 private = action_group->priv;
1433
1434 if (private->translate_notify)
1435 private->translate_notify (private->translate_data);
1436
1437 private->translate_func = func;
1438 private->translate_data = data;
1439 private->translate_notify = notify;
1440}
1441
1442static gchar *
1443dgettext_swapped (const gchar *msgid,
1444 const gchar *domainname)
1445{
1446 /* Pass through g_dgettext if and only if msgid is nonempty. */
1447 if (msgid && *msgid)
1448 return (gchar*) g_dgettext (domainname, msgid);
1449 else
1450 return (gchar*) msgid;
1451}
1452
1453/**
1454 * ctk_action_group_set_translation_domain:
1455 * @action_group: a #CtkActionGroup
1456 * @domain: (allow-none): the translation domain to use for g_dgettext()
1457 * calls, or %NULL to use the domain set with textdomain()
1458 *
1459 * Sets the translation domain and uses g_dgettext() for translating the
1460 * @label and @tooltip of #CtkActionEntrys added by
1461 * ctk_action_group_add_actions().
1462 *
1463 * If you’re not using gettext() for localization, see
1464 * ctk_action_group_set_translate_func().
1465 *
1466 * Since: 2.4
1467 **/
1468void
1469ctk_action_group_set_translation_domain (CtkActionGroup *action_group,
1470 const gchar *domain)
1471{
1472 g_return_if_fail (CTK_IS_ACTION_GROUP (action_group))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((action_group)); GType __t = ((ctk_action_group_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_GROUP (action_group)"); return
; } } while (0)
;
1473
1474 ctk_action_group_set_translate_func (action_group,
1475 (CtkTranslateFunc)dgettext_swapped,
1476 g_strdup (domain)g_strdup_inline (domain),
1477 g_free);
1478}
1479
1480
1481/**
1482 * ctk_action_group_translate_string:
1483 * @action_group: a #CtkActionGroup
1484 * @string: a string
1485 *
1486 * Translates a string using the function set with
1487 * ctk_action_group_set_translate_func(). This
1488 * is mainly intended for language bindings.
1489 *
1490 * Returns: the translation of @string
1491 *
1492 * Since: 2.6
1493 **/
1494const gchar *
1495ctk_action_group_translate_string (CtkActionGroup *action_group,
1496 const gchar *string)
1497{
1498 CtkActionGroupPrivate *private;
1499 CtkTranslateFunc translate_func;
1500 gpointer translate_data;
1501
1502 g_return_val_if_fail (CTK_IS_ACTION_GROUP (action_group), string)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((action_group)); GType __t = ((ctk_action_group_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_GROUP (action_group)"); return
(string); } } while (0)
;
1503
1504 if (string == NULL((void*)0))
1505 return NULL((void*)0);
1506
1507 private = action_group->priv;
1508
1509 translate_func = private->translate_func;
1510 translate_data = private->translate_data;
1511
1512 if (translate_func)
1513 return translate_func (string, translate_data);
1514 else
1515 return string;
1516}
1517
1518/* Protected for use by CtkAction */
1519void
1520_ctk_action_group_emit_connect_proxy (CtkActionGroup *action_group,
1521 CtkAction *action,
1522 CtkWidget *proxy)
1523{
1524 g_signal_emit (action_group, action_group_signals[CONNECT_PROXY], 0,
1525 action, proxy);
1526}
1527
1528void
1529_ctk_action_group_emit_disconnect_proxy (CtkActionGroup *action_group,
1530 CtkAction *action,
1531 CtkWidget *proxy)
1532{
1533 g_signal_emit (action_group, action_group_signals[DISCONNECT_PROXY], 0,
1534 action, proxy);
1535}
1536
1537void
1538_ctk_action_group_emit_pre_activate (CtkActionGroup *action_group,
1539 CtkAction *action)
1540{
1541 g_signal_emit (action_group, action_group_signals[PRE_ACTIVATE], 0, action);
1542}
1543
1544void
1545_ctk_action_group_emit_post_activate (CtkActionGroup *action_group,
1546 CtkAction *action)
1547{
1548 g_signal_emit (action_group, action_group_signals[POST_ACTIVATE], 0, action);
1549}