Bug Summary

File:tests/testgmenu.c
Warning:line 247, column 41
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 testgmenu.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 -pic-is-pie -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 -fdebug-compilation-dir=/rootdir/tests -fcoverage-compilation-dir=/rootdir/tests -resource-dir /usr/lib/llvm-19/lib/clang/19 -D HAVE_CONFIG_H -I . -I .. -I .. -I ../cdk -I ../cdk -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 -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/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -internal-isystem /usr/lib/llvm-19/lib/clang/19/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 -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -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.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-12-18-090527-43637-1 -x c testgmenu.c
1/* testgmenu.c
2 * Copyright (C) 2011 Red Hat, Inc.
3 * Written by Matthias Clasen
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <stdlib.h>
20#include <string.h>
21#include <gio/gio.h>
22#include <ctk/ctk.h>
23
24/* TODO
25 *
26 * - Labeled sections
27 *
28 * - Focus changes. Verify that stopping subscriptions works.
29 *
30 * - Other attributes. What about icons ?
31 */
32
33/* The example menu {{{1 */
34
35static const gchar menu_markup[] =
36 "<interface>\n"
37 "<menu id='edit-menu'>\n"
38 " <section>\n"
39 " <item>\n"
40 " <attribute name='action'>actions.undo</attribute>\n"
41 " <attribute name='label' translatable='yes' context='Stock label'>_Undo</attribute>\n"
42 " </item>\n"
43 " <item>\n"
44 " <attribute name='label' translatable='yes'>Redo</attribute>\n"
45 " <attribute name='action'>actions.redo</attribute>\n"
46 " </item>\n"
47 " </section>\n"
48 " <section/>\n"
49 " <section>\n"
50 " <attribute name='label' translatable='yes'>Copy &amp; Paste</attribute>\n"
51 " <item>\n"
52 " <attribute name='label' translatable='yes'>Cut</attribute>\n"
53 " <attribute name='action'>actions.cut</attribute>\n"
54 " </item>\n"
55 " <item>\n"
56 " <attribute name='label' translatable='yes'>Copy</attribute>\n"
57 " <attribute name='action'>actions.copy</attribute>\n"
58 " </item>\n"
59 " <item>\n"
60 " <attribute name='label' translatable='yes'>Paste</attribute>\n"
61 " <attribute name='action'>actions.paste</attribute>\n"
62 " </item>\n"
63 " </section>\n"
64 " <section>\n"
65 " <item>\n"
66 " <attribute name='label' translatable='yes'>Bold</attribute>\n"
67 " <attribute name='action'>actions.bold</attribute>\n"
68 " </item>\n"
69 " <section id=\"size-placeholder\">\n"
70 " <attribute name=\"label\">Size</attribute>"
71 " </section>\n"
72 " <submenu>\n"
73 " <attribute name='label' translatable='yes'>Language</attribute>\n"
74 " <item>\n"
75 " <attribute name='label' translatable='yes'>Latin</attribute>\n"
76 " <attribute name='action'>actions.lang</attribute>\n"
77 " <attribute name='target'>latin</attribute>\n"
78 " </item>\n"
79 " <item>\n"
80 " <attribute name='label' translatable='yes'>Greek</attribute>\n"
81 " <attribute name='action'>actions.lang</attribute>\n"
82 " <attribute name='target'>greek</attribute>\n"
83 " </item>\n"
84 " <item>\n"
85 " <attribute name='label' translatable='yes'>Urdu</attribute>\n"
86 " <attribute name='action'>actions.lang</attribute>\n"
87 " <attribute name='target'>urdu</attribute>\n"
88 " </item>\n"
89 " </submenu>\n"
90 " </section>\n"
91 "</menu>\n"
92 "</interface>\n";
93
94static GMenuModel *
95get_model (void)
96{
97 GError *error = NULL((void*)0);
98 CtkBuilder *builder;
99 GMenuModel *menu, *section;
100 float i;
101
102 builder = ctk_builder_new ();
103 ctk_builder_add_from_string (builder, menu_markup, -1, &error);
104 g_assert_no_error (error)do { if (error) g_assertion_message_error (((gchar*) 0), "testgmenu.c"
, 104, ((const char*) (__func__)), "error", error, 0, 0); } while
(0)
;
105
106 menu = G_MENU_MODEL (g_object_ref (ctk_builder_get_object (builder, "edit-menu")))((((GMenuModel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((((__typeof__ (ctk_builder_get_object (builder, "edit-menu"
))) (g_object_ref) (ctk_builder_get_object (builder, "edit-menu"
))))), ((g_menu_model_get_type ()))))))
;
107
108 section = G_MENU_MODEL (g_object_ref (ctk_builder_get_object (builder, "size-placeholder")))((((GMenuModel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((((__typeof__ (ctk_builder_get_object (builder, "size-placeholder"
))) (g_object_ref) (ctk_builder_get_object (builder, "size-placeholder"
))))), ((g_menu_model_get_type ()))))))
;
109 g_object_unref (builder);
110
111 for (i = 0.5; i <= 2.0; i += 0.5)
112 {
113 GMenuItem *item;
114 char *target;
115 char *label;
116
117 target = g_strdup_printf ("actions.size::%.1f", i);
118 label = g_strdup_printf ("x %.1f", i);
119 item = g_menu_item_new (label, target);
120 g_menu_append_item (G_MENU (section)((((GMenu*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((section)), ((g_menu_get_type ()))))))
, item);
121 g_free (label);
122 g_free (target);
123 }
124
125 return menu;
126}
127
128/* The example actions {{{1 */
129
130static void
131activate_action (GSimpleAction *action,
132 GVariant *parameter G_GNUC_UNUSED__attribute__ ((__unused__)),
133 gpointer user_data G_GNUC_UNUSED__attribute__ ((__unused__)))
134{
135 g_print ("Action %s activated\n", g_action_get_name (G_ACTION (action)((((GAction*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action)), ((g_action_get_type ()))))))
));
136}
137
138static void
139activate_toggle (GSimpleAction *action,
140 GVariant *parameter G_GNUC_UNUSED__attribute__ ((__unused__)),
141 gpointer user_data G_GNUC_UNUSED__attribute__ ((__unused__)))
142{
143 GVariant *old_state, *new_state;
144
145 old_state = g_action_get_state (G_ACTION (action)((((GAction*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action)), ((g_action_get_type ()))))))
);
146 new_state = g_variant_new_boolean (!g_variant_get_boolean (old_state));
147
148 g_print ("Toggle action %s activated, state changes from %d to %d\n",
149 g_action_get_name (G_ACTION (action)((((GAction*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action)), ((g_action_get_type ()))))))
),
150 g_variant_get_boolean (old_state),
151 g_variant_get_boolean (new_state));
152
153 g_simple_action_set_state (action, new_state);
154 g_variant_unref (old_state);
155}
156
157static void
158activate_radio (GSimpleAction *action,
159 GVariant *parameter,
160 gpointer user_data G_GNUC_UNUSED__attribute__ ((__unused__)))
161{
162 GVariant *old_state, *new_state;
163
164 old_state = g_action_get_state (G_ACTION (action)((((GAction*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action)), ((g_action_get_type ()))))))
);
165 new_state = g_variant_new_string (g_variant_get_string (parameter, NULL((void*)0)));
166
167 g_print ("Radio action %s activated, state changes from %s to %s\n",
168 g_action_get_name (G_ACTION (action)((((GAction*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action)), ((g_action_get_type ()))))))
),
169 g_variant_get_string (old_state, NULL((void*)0)),
170 g_variant_get_string (new_state, NULL((void*)0)));
171
172 g_simple_action_set_state (action, new_state);
173 g_variant_unref (old_state);
174}
175
176static GActionEntry actions[] = {
177 { .name = "undo", .activate = activate_action },
178 { .name = "redo", .activate = activate_action },
179 { .name = "cut", .activate = activate_action },
180 { .name = "copy", .activate = activate_action },
181 { .name = "paste", .activate = activate_action },
182 { .name = "bold", .activate = activate_toggle, .state = "true" },
183 { .name = "lang", .activate = activate_radio, .parameter_type = "s", .state = "'latin'" },
184};
185
186static GActionGroup *
187get_group (void)
188{
189 GSimpleActionGroup *group;
190
191 group = g_simple_action_group_new ();
192
193 g_action_map_add_action_entries (G_ACTION_MAP (group)((((GActionMap*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((group)), ((g_action_map_get_type ()))))))
, actions, G_N_ELEMENTS (actions)(sizeof (actions) / sizeof ((actions)[0])), NULL((void*)0));
194
195 return G_ACTION_GROUP (group)((((GActionGroup*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((group)), ((g_action_group_get_type ()))))))
;
196}
197
198/* The action treeview {{{1 */
199
200static void
201enabled_cell_func (CtkTreeViewColumn *column G_GNUC_UNUSED__attribute__ ((__unused__)),
202 CtkCellRenderer *cell,
203 CtkTreeModel *model,
204 CtkTreeIter *iter,
205 gpointer data)
206{
207 GActionGroup *group = data;
208 gchar *name;
209 gboolean enabled;
210
211 ctk_tree_model_get (model, iter, 0, &name, -1);
212 enabled = g_action_group_get_action_enabled (group, name);
213 g_free (name);
214
215 ctk_cell_renderer_toggle_set_active (CTK_CELL_RENDERER_TOGGLE (cell)((((CtkCellRendererToggle*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((cell)), ((ctk_cell_renderer_toggle_get_type
()))))))
, enabled);
216}
217
218static void
219state_cell_func (CtkTreeViewColumn *column G_GNUC_UNUSED__attribute__ ((__unused__)),
220 CtkCellRenderer *cell,
221 CtkTreeModel *model,
222 CtkTreeIter *iter,
223 gpointer data)
224{
225 GActionGroup *group = data;
226 gchar *name;
227 GVariant *state;
228
229 ctk_tree_model_get (model, iter, 0, &name, -1);
230 state = g_action_group_get_action_state (group, name);
231 g_free (name);
232
233 ctk_cell_renderer_set_visible (cell, FALSE(0));
234 g_object_set (cell, "mode", CTK_CELL_RENDERER_MODE_INERT, NULL((void*)0));
235
236 if (state == NULL((void*)0))
237 return;
238
239 if (g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN((const GVariantType *) "b")) &&
240 CTK_IS_CELL_RENDERER_TOGGLE (cell)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(cell)); GType __t = ((ctk_cell_renderer_toggle_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; }
))))
)
241 {
242 ctk_cell_renderer_set_visible (cell, TRUE(!(0)));
243 g_object_set (cell, "mode", CTK_CELL_RENDERER_MODE_ACTIVATABLE, NULL((void*)0));
244 ctk_cell_renderer_toggle_set_active (CTK_CELL_RENDERER_TOGGLE (cell)((((CtkCellRendererToggle*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((cell)), ((ctk_cell_renderer_toggle_get_type
()))))))
,
245 g_variant_get_boolean (state));
246 }
247 else if (g_variant_is_of_type (state, G_VARIANT_TYPE_STRING((const GVariantType *) "s")) &&
Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption
248 CTK_IS_CELL_RENDERER_COMBO (cell)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(cell)); GType __t = ((ctk_cell_renderer_combo_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; }
))))
)
249 {
250 ctk_cell_renderer_set_visible (cell, TRUE(!(0)));
251 g_object_set (cell, "mode", CTK_CELL_RENDERER_MODE_EDITABLE, NULL((void*)0));
252 g_object_set (cell, "text", g_variant_get_string (state, NULL((void*)0)), NULL((void*)0));
253 }
254
255 g_variant_unref (state);
256}
257
258static void
259enabled_cell_toggled (CtkCellRendererToggle *cell G_GNUC_UNUSED__attribute__ ((__unused__)),
260 const gchar *path_str,
261 CtkTreeModel *model)
262{
263 GActionGroup *group;
264 GAction *action;
265 gchar *name;
266 CtkTreePath *path;
267 CtkTreeIter iter;
268 gboolean enabled;
269
270 group = g_object_get_data (G_OBJECT (model)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((model)), (((GType) ((20) << (2))))))))
, "group");
271 path = ctk_tree_path_new_from_string (path_str);
272 ctk_tree_model_get_iter (model, &iter, path);
273 ctk_tree_model_get (model, &iter, 0, &name, -1);
274
275 enabled = g_action_group_get_action_enabled (group, name);
276 action = g_action_map_lookup_action (G_ACTION_MAP (group)((((GActionMap*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((group)), ((g_action_map_get_type ()))))))
, name);
277 g_simple_action_set_enabled (G_SIMPLE_ACTION (action)((((GSimpleAction*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action)), ((g_simple_action_get_type ()))))))
, !enabled);
278
279 ctk_tree_model_row_changed (model, path, &iter);
280
281 g_free (name);
282 ctk_tree_path_free (path);
283}
284
285static void
286state_cell_toggled (CtkCellRendererToggle *cell G_GNUC_UNUSED__attribute__ ((__unused__)),
287 const gchar *path_str,
288 CtkTreeModel *model)
289{
290 GActionGroup *group;
291 GAction *action;
292 gchar *name;
293 CtkTreePath *path;
294 CtkTreeIter iter;
295 GVariant *state;
296
297 group = g_object_get_data (G_OBJECT (model)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((model)), (((GType) ((20) << (2))))))))
, "group");
298 path = ctk_tree_path_new_from_string (path_str);
299 ctk_tree_model_get_iter (model, &iter, path);
300 ctk_tree_model_get (model, &iter, 0, &name, -1);
301
302 state = g_action_group_get_action_state (group, name);
303 action = g_action_map_lookup_action (G_ACTION_MAP (group)((((GActionMap*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((group)), ((g_action_map_get_type ()))))))
, name);
304 if (state && g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN((const GVariantType *) "b")))
305 {
306 gboolean b;
307
308 b = g_variant_get_boolean (state);
309 g_simple_action_set_state (G_SIMPLE_ACTION (action)((((GSimpleAction*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action)), ((g_simple_action_get_type ()))))))
, g_variant_new_boolean (!b));
310 }
311 else
312 {
313 /* nothing to do */
314 }
315
316 ctk_tree_model_row_changed (model, path, &iter);
317
318 g_free (name);
319 ctk_tree_path_free (path);
320 if (state)
321 g_variant_unref (state);
322}
323
324static void
325state_cell_edited (CtkCellRendererCombo *cell G_GNUC_UNUSED__attribute__ ((__unused__)),
326 const gchar *path_str,
327 const gchar *new_text,
328 CtkTreeModel *model)
329{
330 GActionGroup *group;
331 GAction *action;
332 gchar *name;
333 CtkTreePath *path;
334 CtkTreeIter iter;
335
336 group = g_object_get_data (G_OBJECT (model)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((model)), (((GType) ((20) << (2))))))))
, "group");
337 path = ctk_tree_path_new_from_string (path_str);
338 ctk_tree_model_get_iter (model, &iter, path);
339 ctk_tree_model_get (model, &iter, 0, &name, -1);
340 action = g_action_map_lookup_action (G_ACTION_MAP (group)((((GActionMap*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((group)), ((g_action_map_get_type ()))))))
, name);
341 g_simple_action_set_state (G_SIMPLE_ACTION (action)((((GSimpleAction*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action)), ((g_simple_action_get_type ()))))))
, g_variant_new_string (new_text));
342
343 ctk_tree_model_row_changed (model, path, &iter);
344
345 g_free (name);
346 ctk_tree_path_free (path);
347}
348
349static CtkWidget *
350create_action_treeview (GActionGroup *group)
351{
352 CtkWidget *tv;
353 CtkListStore *store;
354 CtkListStore *values;
355 CtkTreeIter iter;
356 CtkTreeViewColumn *column;
357 CtkCellRenderer *cell;
358 gchar **actions;
359 gint i;
360
361 store = ctk_list_store_new (2, G_TYPE_STRING((GType) ((16) << (2))), G_TYPE_STRING((GType) ((16) << (2))));
362 actions = g_action_group_list_actions (group);
363 for (i = 0; actions[i]; i++)
364 {
365 ctk_list_store_append (store, &iter);
366 ctk_list_store_set (store, &iter, 0, actions[i], -1);
367 }
368 g_strfreev (actions);
369 g_object_set_data (G_OBJECT (store)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((store)), (((GType) ((20) << (2))))))))
, "group", group);
370
371 tv = ctk_tree_view_new ();
372
373 g_signal_connect_swapped (group, "action-enabled-changed",g_signal_connect_data ((group), ("action-enabled-changed"), (
((GCallback) (ctk_widget_queue_draw))), (tv), ((void*)0), G_CONNECT_SWAPPED
)
374 G_CALLBACK (ctk_widget_queue_draw), tv)g_signal_connect_data ((group), ("action-enabled-changed"), (
((GCallback) (ctk_widget_queue_draw))), (tv), ((void*)0), G_CONNECT_SWAPPED
)
;
375 g_signal_connect_swapped (group, "action-state-changed",g_signal_connect_data ((group), ("action-state-changed"), (((
GCallback) (ctk_widget_queue_draw))), (tv), ((void*)0), G_CONNECT_SWAPPED
)
376 G_CALLBACK (ctk_widget_queue_draw), tv)g_signal_connect_data ((group), ("action-state-changed"), (((
GCallback) (ctk_widget_queue_draw))), (tv), ((void*)0), G_CONNECT_SWAPPED
)
;
377
378 ctk_tree_view_set_model (CTK_TREE_VIEW (tv)((((CtkTreeView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tv)), ((ctk_tree_view_get_type ()))))))
, CTK_TREE_MODEL (store)((((CtkTreeModel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((store)), ((ctk_tree_model_get_type ()))))))
);
379
380 cell = ctk_cell_renderer_text_new ();
381 column = ctk_tree_view_column_new_with_attributes ("Action", cell,
382 "text", 0,
383 NULL((void*)0));
384 ctk_tree_view_append_column (CTK_TREE_VIEW (tv)((((CtkTreeView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tv)), ((ctk_tree_view_get_type ()))))))
, column);
385
386 column = ctk_tree_view_column_new ();
387 ctk_tree_view_column_set_title (column, "Enabled");
388 cell = ctk_cell_renderer_toggle_new ();
389 ctk_tree_view_column_pack_start (column, cell, FALSE(0));
390 ctk_tree_view_column_set_cell_data_func (column, cell, enabled_cell_func, group, NULL((void*)0));
391 g_signal_connect (cell, "toggled", G_CALLBACK (enabled_cell_toggled), store)g_signal_connect_data ((cell), ("toggled"), (((GCallback) (enabled_cell_toggled
))), (store), ((void*)0), (GConnectFlags) 0)
;
392 ctk_tree_view_append_column (CTK_TREE_VIEW (tv)((((CtkTreeView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tv)), ((ctk_tree_view_get_type ()))))))
, column);
393
394 column = ctk_tree_view_column_new ();
395 ctk_tree_view_column_set_title (column, "State");
396 cell = ctk_cell_renderer_toggle_new ();
397 ctk_tree_view_column_pack_start (column, cell, FALSE(0));
398 ctk_tree_view_column_set_cell_data_func (column, cell, state_cell_func, group, NULL((void*)0));
399 g_signal_connect (cell, "toggled", G_CALLBACK (state_cell_toggled), store)g_signal_connect_data ((cell), ("toggled"), (((GCallback) (state_cell_toggled
))), (store), ((void*)0), (GConnectFlags) 0)
;
400 cell = ctk_cell_renderer_combo_new ();
401 values = ctk_list_store_new (1, G_TYPE_STRING((GType) ((16) << (2))));
402 ctk_list_store_append (values, &iter);
403 ctk_list_store_set (values, &iter, 0, "latin", -1);
404 ctk_list_store_append (values, &iter);
405 ctk_list_store_set (values, &iter, 0, "greek", -1);
406 ctk_list_store_append (values, &iter);
407 ctk_list_store_set (values, &iter, 0, "urdu", -1);
408 ctk_list_store_append (values, &iter);
409 ctk_list_store_set (values, &iter, 0, "sumerian", -1);
410 g_object_set (cell,
411 "has-entry", FALSE(0),
412 "model", values,
413 "text-column", 0,
414 "editable", TRUE(!(0)),
415 NULL((void*)0));
416 ctk_tree_view_column_pack_start (column, cell, FALSE(0));
417 ctk_tree_view_column_set_cell_data_func (column, cell, state_cell_func, group, NULL((void*)0));
418 g_signal_connect (cell, "edited", G_CALLBACK (state_cell_edited), store)g_signal_connect_data ((cell), ("edited"), (((GCallback) (state_cell_edited
))), (store), ((void*)0), (GConnectFlags) 0)
;
419 ctk_tree_view_append_column (CTK_TREE_VIEW (tv)((((CtkTreeView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((tv)), ((ctk_tree_view_get_type ()))))))
, column);
420
421 return tv;
422}
423
424/* Dynamic menu changes {{{1 */
425
426static void
427toggle_sumerian (CtkToggleButton *button,
428 gpointer data G_GNUC_UNUSED__attribute__ ((__unused__)))
429{
430 GMenuModel *model;
431 gboolean adding;
432 GMenuModel *m;
433
434 model = g_object_get_data (G_OBJECT (button)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button)), (((GType) ((20) << (2))))))))
, "model");
435
436 adding = ctk_toggle_button_get_active (button);
437
438 m = g_menu_model_get_item_link (model, g_menu_model_get_n_items (model) - 1, G_MENU_LINK_SECTION"section");
439 m = g_menu_model_get_item_link (m, g_menu_model_get_n_items (m) - 1, G_MENU_LINK_SUBMENU"submenu");
440 if (adding)
441 g_menu_append (G_MENU (m)((((GMenu*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((m)), ((g_menu_get_type ()))))))
, "Sumerian", "lang::sumerian");
442 else
443 g_menu_remove (G_MENU (m)((((GMenu*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((m)), ((g_menu_get_type ()))))))
, g_menu_model_get_n_items (m) - 1);
444}
445
446static void
447action_list_add (CtkTreeModel *store,
448 const gchar *action)
449{
450 CtkTreeIter iter;
451
452 ctk_list_store_append (CTK_LIST_STORE (store)((((CtkListStore*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((store)), ((ctk_list_store_get_type ()))))))
, &iter);
453 ctk_list_store_set (CTK_LIST_STORE (store)((((CtkListStore*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((store)), ((ctk_list_store_get_type ()))))))
, &iter, 0, action, -1);
454}
455
456static void
457action_list_remove (CtkTreeModel *store,
458 const gchar *action)
459{
460 CtkTreeIter iter;
461 gchar *text;
462
463 ctk_tree_model_get_iter_first (store, &iter);
464 do {
465 ctk_tree_model_get (store, &iter, 0, &text, -1);
466 if (g_strcmp0 (action, text) == 0)
467 {
468 g_free (text);
469 ctk_list_store_remove (CTK_LIST_STORE (store)((((CtkListStore*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((store)), ((ctk_list_store_get_type ()))))))
, &iter);
470 break;
471 }
472 g_free (text);
473 } while (ctk_tree_model_iter_next (store, &iter));
474}
475
476static void
477toggle_italic (CtkToggleButton *button, gpointer data)
478{
479 GMenuModel *model;
480 GActionGroup *group;
481 gboolean adding;
482 GMenuModel *m;
483 CtkTreeView *tv = data;
484 CtkTreeModel *store;
485
486 model = g_object_get_data (G_OBJECT (button)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button)), (((GType) ((20) << (2))))))))
, "model");
487 group = g_object_get_data (G_OBJECT (button)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button)), (((GType) ((20) << (2))))))))
, "group");
488
489 store = ctk_tree_view_get_model (tv);
490
491 adding = ctk_toggle_button_get_active (button);
492
493 m = g_menu_model_get_item_link (model, g_menu_model_get_n_items (model) - 1, G_MENU_LINK_SECTION"section");
494 if (adding)
495 {
496 GSimpleAction *action;
497
498 action = g_simple_action_new_stateful ("italic", NULL((void*)0), g_variant_new_boolean (FALSE(0)));
499 g_action_map_add_action (G_ACTION_MAP (group)((((GActionMap*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((group)), ((g_action_map_get_type ()))))))
, G_ACTION (action)((((GAction*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action)), ((g_action_get_type ()))))))
);
500 g_signal_connect (action, "activate", G_CALLBACK (activate_toggle), NULL)g_signal_connect_data ((action), ("activate"), (((GCallback) (
activate_toggle))), (((void*)0)), ((void*)0), (GConnectFlags)
0)
;
501 g_object_unref (action);
502 action_list_add (store, "italic");
503 g_menu_insert (G_MENU (m)((((GMenu*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((m)), ((g_menu_get_type ()))))))
, 1, "Italic", "italic");
504 }
505 else
506 {
507 g_action_map_remove_action (G_ACTION_MAP (group)((((GActionMap*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((group)), ((g_action_map_get_type ()))))))
, "italic");
508 action_list_remove (store, "italic");
509 g_menu_remove (G_MENU (m)((((GMenu*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((m)), ((g_menu_get_type ()))))))
, 1);
510 }
511}
512
513static void
514toggle_speed (CtkToggleButton *button, gpointer data)
515{
516 GMenuModel *model;
517 GActionGroup *group;
518 gboolean adding;
519 GMenuModel *m;
520 CtkTreeView *tv = data;
521 CtkTreeModel *store;
522
523 model = g_object_get_data (G_OBJECT (button)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button)), (((GType) ((20) << (2))))))))
, "model");
524 group = g_object_get_data (G_OBJECT (button)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button)), (((GType) ((20) << (2))))))))
, "group");
525
526 store = ctk_tree_view_get_model (tv);
527
528 adding = ctk_toggle_button_get_active (button);
529
530 m = g_menu_model_get_item_link (model, 1, G_MENU_LINK_SECTION"section");
531 if (adding)
532 {
533 GSimpleAction *action;
534 GMenu *submenu;
535
536 action = g_simple_action_new ("faster", NULL((void*)0));
537 g_action_map_add_action (G_ACTION_MAP (group)((((GActionMap*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((group)), ((g_action_map_get_type ()))))))
, G_ACTION (action)((((GAction*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action)), ((g_action_get_type ()))))))
);
538 g_signal_connect (action, "activate", G_CALLBACK (activate_action), NULL)g_signal_connect_data ((action), ("activate"), (((GCallback) (
activate_action))), (((void*)0)), ((void*)0), (GConnectFlags)
0)
;
539 g_object_unref (action);
540
541 action = g_simple_action_new ("slower", NULL((void*)0));
542 g_action_map_add_action (G_ACTION_MAP (group)((((GActionMap*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((group)), ((g_action_map_get_type ()))))))
, G_ACTION (action)((((GAction*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((action)), ((g_action_get_type ()))))))
);
543 g_signal_connect (action, "activate", G_CALLBACK (activate_action), NULL)g_signal_connect_data ((action), ("activate"), (((GCallback) (
activate_action))), (((void*)0)), ((void*)0), (GConnectFlags)
0)
;
544 g_object_unref (action);
545
546 action_list_add (store, "faster");
547 action_list_add (store, "slower");
548
549 submenu = g_menu_new ();
550 g_menu_append (submenu, "Faster", "faster");
551 g_menu_append (submenu, "Slower", "slower");
552 g_menu_append_submenu (G_MENU (m)((((GMenu*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((m)), ((g_menu_get_type ()))))))
, "Speed", G_MENU_MODEL (submenu)((((GMenuModel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((submenu)), ((g_menu_model_get_type ()))))))
);
553 }
554 else
555 {
556 g_action_map_remove_action (G_ACTION_MAP (group)((((GActionMap*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((group)), ((g_action_map_get_type ()))))))
, "faster");
557 g_action_map_remove_action (G_ACTION_MAP (group)((((GActionMap*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((group)), ((g_action_map_get_type ()))))))
, "slower");
558
559 action_list_remove (store, "faster");
560 action_list_remove (store, "slower");
561
562 g_menu_remove (G_MENU (m)((((GMenu*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((m)), ((g_menu_get_type ()))))))
, g_menu_model_get_n_items (m) - 1);
563 }
564}
565static CtkWidget *
566create_add_remove_buttons (GActionGroup *group,
567 GMenuModel *model,
568 CtkWidget *treeview)
569{
570 CtkWidget *box;
571 CtkWidget *button;
572
573 box = ctk_box_new (CTK_ORIENTATION_VERTICAL, 6);
574
575 button = ctk_check_button_new_with_label ("Add Italic");
576 ctk_container_add (CTK_CONTAINER (box)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_container_get_type ()))))))
, button);
577
578 g_object_set_data (G_OBJECT (button)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button)), (((GType) ((20) << (2))))))))
, "group", group);
579 g_object_set_data (G_OBJECT (button)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button)), (((GType) ((20) << (2))))))))
, "model", model);
580
581 g_signal_connect (button, "toggled",g_signal_connect_data ((button), ("toggled"), (((GCallback) (
toggle_italic))), (treeview), ((void*)0), (GConnectFlags) 0)
582 G_CALLBACK (toggle_italic), treeview)g_signal_connect_data ((button), ("toggled"), (((GCallback) (
toggle_italic))), (treeview), ((void*)0), (GConnectFlags) 0)
;
583
584 button = ctk_check_button_new_with_label ("Add Sumerian");
585 ctk_container_add (CTK_CONTAINER (box)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_container_get_type ()))))))
, button);
586
587 g_object_set_data (G_OBJECT (button)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button)), (((GType) ((20) << (2))))))))
, "group", group);
588 g_object_set_data (G_OBJECT (button)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button)), (((GType) ((20) << (2))))))))
, "model", model);
589
590 g_signal_connect (button, "toggled",g_signal_connect_data ((button), ("toggled"), (((GCallback) (
toggle_sumerian))), (((void*)0)), ((void*)0), (GConnectFlags)
0)
591 G_CALLBACK (toggle_sumerian), NULL)g_signal_connect_data ((button), ("toggled"), (((GCallback) (
toggle_sumerian))), (((void*)0)), ((void*)0), (GConnectFlags)
0)
;
592
593 button = ctk_check_button_new_with_label ("Add Speed");
594 ctk_container_add (CTK_CONTAINER (box)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_container_get_type ()))))))
, button);
595
596 g_object_set_data (G_OBJECT (button)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button)), (((GType) ((20) << (2))))))))
, "group", group);
597 g_object_set_data (G_OBJECT (button)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button)), (((GType) ((20) << (2))))))))
, "model", model);
598
599 g_signal_connect (button, "toggled",g_signal_connect_data ((button), ("toggled"), (((GCallback) (
toggle_speed))), (treeview), ((void*)0), (GConnectFlags) 0)
600 G_CALLBACK (toggle_speed), treeview)g_signal_connect_data ((button), ("toggled"), (((GCallback) (
toggle_speed))), (treeview), ((void*)0), (GConnectFlags) 0)
;
601 return box;
602}
603
604/* main {{{1 */
605
606#define BUS_NAME"org.ctk.TestMenus" "org.ctk.TestMenus"
607#define OBJ_PATH"/org/ctk/TestMenus" "/org/ctk/TestMenus"
608
609static gboolean
610on_delete_event (CtkWidget *widget G_GNUC_UNUSED__attribute__ ((__unused__)),
611 CdkEvent *event G_GNUC_UNUSED__attribute__ ((__unused__)),
612 gpointer user_data G_GNUC_UNUSED__attribute__ ((__unused__)))
613{
614 ctk_main_quit ();
615 return TRUE(!(0));
616}
617
618int
619main (int argc, char *argv[])
620{
621 CtkWidget *window;
622 CtkWidget *box;
623 GMenuModel *model;
624 GActionGroup *group;
625 GDBusConnection *bus;
626 GError *error = NULL((void*)0);
627 gboolean do_export = FALSE(0);
628 gboolean do_import = FALSE(0);
629 GOptionEntry entries[] = {
630 { "export", 0, 0, G_OPTION_ARG_NONE, &do_export, "Export actions and menus over D-Bus", NULL((void*)0) },
631 { "import", 0, 0, G_OPTION_ARG_NONE, &do_import, "Use exported actions and menus", NULL((void*)0) },
632 { NULL((void*)0), }
633 };
634
635 ctk_init_with_args (&argc, &argv, NULL((void*)0), entries, NULL((void*)0), NULL((void*)0));
636
637 if (do_export && do_import)
638 {
639 g_error ("can't have it both ways\n");
640 exit (1);
641 }
642
643 window = ctk_window_new (CTK_WINDOW_TOPLEVEL);
644 g_signal_connect (window, "delete-event", G_CALLBACK(on_delete_event), NULL)g_signal_connect_data ((window), ("delete-event"), (((GCallback
) (on_delete_event))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
;
645 box = ctk_box_new (CTK_ORIENTATION_VERTICAL, 6);
646 ctk_container_add (CTK_CONTAINER (window)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window)), ((ctk_container_get_type ()))))))
, box);
647
648 bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL((void*)0), NULL((void*)0));
649
650 if (do_import)
651 {
652 g_print ("Getting menus from the bus...\n");
653 model = (GMenuModel*)g_dbus_menu_model_get (bus, BUS_NAME"org.ctk.TestMenus", OBJ_PATH"/org/ctk/TestMenus");
654 g_print ("Getting actions from the bus...\n");
655 group = (GActionGroup*)g_dbus_action_group_get (bus, BUS_NAME"org.ctk.TestMenus", OBJ_PATH"/org/ctk/TestMenus");
656 }
657 else
658 {
659 CtkWidget *tv;
660 CtkWidget *buttons;
661
662 group = get_group ();
663 model = get_model ();
664
665 tv = create_action_treeview (group);
666 ctk_container_add (CTK_CONTAINER (box)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_container_get_type ()))))))
, tv);
667 buttons = create_add_remove_buttons (group, model, tv);
668 ctk_container_add (CTK_CONTAINER (box)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_container_get_type ()))))))
, buttons);
669 }
670
671 if (do_export)
672 {
673 g_print ("Exporting menus on the bus...\n");
674 if (!g_dbus_connection_export_menu_model (bus, OBJ_PATH"/org/ctk/TestMenus", model, &error))
675 {
676 g_warning ("Menu export failed: %s", error->message);
677 exit (1);
678 }
679 g_print ("Exporting actions on the bus...\n");
680 if (!g_dbus_connection_export_action_group (bus, OBJ_PATH"/org/ctk/TestMenus", group, &error))
681 {
682 g_warning ("Action export failed: %s", error->message);
683 exit (1);
684 }
685 g_bus_own_name_on_connection (bus, BUS_NAME"org.ctk.TestMenus", 0, NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0));
686 }
687 else
688 {
689 CtkWidget *button;
690
691 button = ctk_menu_button_new ();
692 ctk_button_set_label (CTK_BUTTON (button)((((CtkButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button)), ((ctk_button_get_type ()))))))
, "Click here");
693 ctk_menu_button_set_use_popover (CTK_MENU_BUTTON (button)((((CtkMenuButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button)), ((ctk_menu_button_get_type ()))))))
, TRUE(!(0)));
694 ctk_menu_button_set_menu_model (CTK_MENU_BUTTON (button)((((CtkMenuButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button)), ((ctk_menu_button_get_type ()))))))
, model);
695 ctk_widget_insert_action_group (button, "actions", group);
696 ctk_container_add (CTK_CONTAINER (box)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_container_get_type ()))))))
, button);
697 }
698
699 ctk_widget_show_all (window);
700
701 ctk_main ();
702
703 return 0;
704}
705
706/* Epilogue {{{1 */
707/* vim:set foldmethod=marker: */