File: | ctk/ctkmenutrackeritem.c |
Warning: | line 410, column 41 Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* |
2 | * Copyright © 2013 Canonical Limited |
3 | * |
4 | * This library is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU Lesser General Public |
6 | * License as published by the Free Software Foundation; either |
7 | * version 2 of the licence, or (at your option) any later version. |
8 | * |
9 | * This library is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * Lesser General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU Lesser General Public |
15 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
16 | * |
17 | * Author: Ryan Lortie <desrt@desrt.ca> |
18 | */ |
19 | |
20 | #include "config.h" |
21 | |
22 | #include "ctkmenutrackeritem.h" |
23 | #include "ctkactionmuxer.h" |
24 | #include "ctkdebug.h" |
25 | |
26 | #include "ctkactionmuxer.h" |
27 | |
28 | #include <string.h> |
29 | |
30 | /*< private > |
31 | * SECTION:ctkmenutrackeritem |
32 | * @Title: CtkMenuTrackerItem |
33 | * @Short_description: Small helper for model menu items |
34 | * |
35 | * A #CtkMenuTrackerItem is a small helper class used by #CtkMenuTracker to |
36 | * represent menu items. It has one of three classes: normal item, separator, |
37 | * or submenu. |
38 | * |
39 | * If an item is one of the non-normal classes (submenu, separator), only the |
40 | * label of the item needs to be respected. Otherwise, all the properties |
41 | * of the item contribute to the item’s appearance and state. |
42 | * |
43 | * Implementing the appearance of the menu item is up to toolkits, and certain |
44 | * toolkits may choose to ignore certain properties, like icon or accel. The |
45 | * role of the item determines its accessibility role, along with its |
46 | * decoration if the CtkMenuTrackerItem::toggled property is true. As an |
47 | * example, if the item has the role %CTK_MENU_TRACKER_ITEM_ROLE_CHECK and |
48 | * CtkMenuTrackerItem::toggled is %FALSE, its accessible role should be that of |
49 | * a check menu item, and no decoration should be drawn. But if |
50 | * CtkMenuTrackerItem::toggled is %TRUE, a checkmark should be drawn. |
51 | * |
52 | * All properties except for the two class-determining properties, |
53 | * CtkMenuTrackerItem::is-separator and CtkMenuTrackerItem::has-submenu are |
54 | * allowed to change, so listen to the notify signals to update your item's |
55 | * appearance. When using a GObject library, this can conveniently be done |
56 | * with g_object_bind_property() and #GBinding, and this is how this is |
57 | * implemented in CTK+; the appearance side is implemented in #CtkModelMenuItem. |
58 | * |
59 | * When an item is clicked, simply call ctk_menu_tracker_item_activated() in |
60 | * response. The #CtkMenuTrackerItem will take care of everything related to |
61 | * activating the item and will itself update the state of all items in |
62 | * response. |
63 | * |
64 | * Submenus are a special case of menu item. When an item is a submenu, you |
65 | * should create a submenu for it with ctk_menu_tracker_new_item_for_submenu(), |
66 | * and apply the same menu tracking logic you would for a toplevel menu. |
67 | * Applications using submenus may want to lazily build their submenus in |
68 | * response to the user clicking on it, as building a submenu may be expensive. |
69 | * |
70 | * Thus, the submenu has two special controls -- the submenu’s visibility |
71 | * should be controlled by the CtkMenuTrackerItem::submenu-shown property, |
72 | * and if a user clicks on the submenu, do not immediately show the menu, |
73 | * but call ctk_menu_tracker_item_request_submenu_shown() and wait for the |
74 | * CtkMenuTrackerItem::submenu-shown property to update. If the user navigates, |
75 | * the application may want to be notified so it can cancel the expensive |
76 | * operation that it was using to build the submenu. Thus, |
77 | * ctk_menu_tracker_item_request_submenu_shown() takes a boolean parameter. |
78 | * Use %TRUE when the user wants to open the submenu, and %FALSE when the |
79 | * user wants to close the submenu. |
80 | */ |
81 | |
82 | typedef GObjectClass CtkMenuTrackerItemClass; |
83 | |
84 | struct _CtkMenuTrackerItem |
85 | { |
86 | GObject parent_instance; |
87 | |
88 | CtkActionObservable *observable; |
89 | gchar *action_namespace; |
90 | gchar *action_and_target; |
91 | GMenuItem *item; |
92 | CtkMenuTrackerItemRole role : 4; |
93 | guint is_separator : 1; |
94 | guint can_activate : 1; |
95 | guint sensitive : 1; |
96 | guint toggled : 1; |
97 | guint submenu_shown : 1; |
98 | guint submenu_requested : 1; |
99 | guint hidden_when : 2; |
100 | guint is_visible : 1; |
101 | }; |
102 | |
103 | #define HIDDEN_NEVER0 0 |
104 | #define HIDDEN_WHEN_MISSING1 1 |
105 | #define HIDDEN_WHEN_DISABLED2 2 |
106 | #define HIDDEN_WHEN_ALWAYS3 3 |
107 | |
108 | enum { |
109 | PROP_0, |
110 | PROP_IS_SEPARATOR, |
111 | PROP_LABEL, |
112 | PROP_ICON, |
113 | PROP_VERB_ICON, |
114 | PROP_SENSITIVE, |
115 | PROP_ROLE, |
116 | PROP_TOGGLED, |
117 | PROP_ACCEL, |
118 | PROP_SUBMENU_SHOWN, |
119 | PROP_IS_VISIBLE, |
120 | N_PROPS |
121 | }; |
122 | |
123 | static GParamSpec *ctk_menu_tracker_item_pspecs[N_PROPS]; |
124 | |
125 | static void ctk_menu_tracker_item_init_observer_iface (CtkActionObserverInterface *iface); |
126 | G_DEFINE_TYPE_WITH_CODE (CtkMenuTrackerItem, ctk_menu_tracker_item, G_TYPE_OBJECT,static void ctk_menu_tracker_item_init (CtkMenuTrackerItem *self ); static void ctk_menu_tracker_item_class_init (CtkMenuTrackerItemClass *klass); static GType ctk_menu_tracker_item_get_type_once (void ); static gpointer ctk_menu_tracker_item_parent_class = ((void *)0); static gint CtkMenuTrackerItem_private_offset; static void ctk_menu_tracker_item_class_intern_init (gpointer klass) { ctk_menu_tracker_item_parent_class = g_type_class_peek_parent (klass); if (CtkMenuTrackerItem_private_offset != 0) g_type_class_adjust_private_offset (klass, &CtkMenuTrackerItem_private_offset ); ctk_menu_tracker_item_class_init ((CtkMenuTrackerItemClass *) klass); } __attribute__ ((__unused__)) static inline gpointer ctk_menu_tracker_item_get_instance_private (CtkMenuTrackerItem *self) { return (((gpointer) ((guint8*) (self) + (glong) (CtkMenuTrackerItem_private_offset )))); } GType ctk_menu_tracker_item_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_menu_tracker_item_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_menu_tracker_item_get_type_once (void) { GType g_define_type_id = g_type_register_static_simple (((GType) ((20) << (2))), g_intern_static_string ("CtkMenuTrackerItem" ), sizeof (CtkMenuTrackerItemClass), (GClassInitFunc)(void (* )(void)) ctk_menu_tracker_item_class_intern_init, sizeof (CtkMenuTrackerItem ), (GInstanceInitFunc)(void (*)(void)) ctk_menu_tracker_item_init , (GTypeFlags) 0); { {{ const GInterfaceInfo g_implement_interface_info = { (GInterfaceInitFunc)(void (*)(void)) ctk_menu_tracker_item_init_observer_iface , ((void*)0), ((void*)0) }; g_type_add_interface_static (g_define_type_id , (ctk_action_observer_get_type ()), &g_implement_interface_info ); };} } return g_define_type_id; } |
127 | G_IMPLEMENT_INTERFACE (CTK_TYPE_ACTION_OBSERVER, ctk_menu_tracker_item_init_observer_iface))static void ctk_menu_tracker_item_init (CtkMenuTrackerItem *self ); static void ctk_menu_tracker_item_class_init (CtkMenuTrackerItemClass *klass); static GType ctk_menu_tracker_item_get_type_once (void ); static gpointer ctk_menu_tracker_item_parent_class = ((void *)0); static gint CtkMenuTrackerItem_private_offset; static void ctk_menu_tracker_item_class_intern_init (gpointer klass) { ctk_menu_tracker_item_parent_class = g_type_class_peek_parent (klass); if (CtkMenuTrackerItem_private_offset != 0) g_type_class_adjust_private_offset (klass, &CtkMenuTrackerItem_private_offset ); ctk_menu_tracker_item_class_init ((CtkMenuTrackerItemClass *) klass); } __attribute__ ((__unused__)) static inline gpointer ctk_menu_tracker_item_get_instance_private (CtkMenuTrackerItem *self) { return (((gpointer) ((guint8*) (self) + (glong) (CtkMenuTrackerItem_private_offset )))); } GType ctk_menu_tracker_item_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_menu_tracker_item_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_menu_tracker_item_get_type_once (void) { GType g_define_type_id = g_type_register_static_simple (((GType) ((20) << (2))), g_intern_static_string ("CtkMenuTrackerItem" ), sizeof (CtkMenuTrackerItemClass), (GClassInitFunc)(void (* )(void)) ctk_menu_tracker_item_class_intern_init, sizeof (CtkMenuTrackerItem ), (GInstanceInitFunc)(void (*)(void)) ctk_menu_tracker_item_init , (GTypeFlags) 0); { {{ const GInterfaceInfo g_implement_interface_info = { (GInterfaceInitFunc)(void (*)(void)) ctk_menu_tracker_item_init_observer_iface , ((void*)0), ((void*)0) }; g_type_add_interface_static (g_define_type_id , (ctk_action_observer_get_type ()), &g_implement_interface_info ); };} } return g_define_type_id; } |
128 | |
129 | GType |
130 | ctk_menu_tracker_item_role_get_type (void) |
131 | { |
132 | static gsize ctk_menu_tracker_item_role_type; |
133 | |
134 | if (g_once_init_enter (&ctk_menu_tracker_item_role_type)(__extension__ ({ _Static_assert (sizeof *(&ctk_menu_tracker_item_role_type ) == sizeof (gpointer), "Expression evaluates to false"); (void ) (0 ? (gpointer) *(&ctk_menu_tracker_item_role_type) : ( (void*)0)); (!(__extension__ ({ _Static_assert (sizeof *(& ctk_menu_tracker_item_role_type) == sizeof (gpointer), "Expression evaluates to false" ); __typeof__ (*(&ctk_menu_tracker_item_role_type)) gapg_temp_newval ; __typeof__ ((&ctk_menu_tracker_item_role_type)) gapg_temp_atomic = (&ctk_menu_tracker_item_role_type); __atomic_load (gapg_temp_atomic , &gapg_temp_newval, 5); gapg_temp_newval; })) && g_once_init_enter (&ctk_menu_tracker_item_role_type)); } ))) |
135 | { |
136 | static const GEnumValue values[] = { |
137 | { CTK_MENU_TRACKER_ITEM_ROLE_NORMAL, "CTK_MENU_TRACKER_ITEM_ROLE_NORMAL", "normal" }, |
138 | { CTK_MENU_TRACKER_ITEM_ROLE_CHECK, "CTK_MENU_TRACKER_ITEM_ROLE_CHECK", "check" }, |
139 | { CTK_MENU_TRACKER_ITEM_ROLE_RADIO, "CTK_MENU_TRACKER_ITEM_ROLE_RADIO", "radio" }, |
140 | { 0, NULL((void*)0), NULL((void*)0) } |
141 | }; |
142 | GType type; |
143 | |
144 | type = g_enum_register_static ("CtkMenuTrackerItemRole", values); |
145 | |
146 | g_once_init_leave (&ctk_menu_tracker_item_role_type, type)(__extension__ ({ _Static_assert (sizeof *(&ctk_menu_tracker_item_role_type ) == sizeof (gpointer), "Expression evaluates to false"); 0 ? (void) (*(&ctk_menu_tracker_item_role_type) = (type)) : ( void) 0; g_once_init_leave ((&ctk_menu_tracker_item_role_type ), (gsize) (type)); })); |
147 | } |
148 | |
149 | return ctk_menu_tracker_item_role_type; |
150 | } |
151 | |
152 | static void |
153 | ctk_menu_tracker_item_get_property (GObject *object, |
154 | guint prop_id, |
155 | GValue *value, |
156 | GParamSpec *pspec) |
157 | { |
158 | CtkMenuTrackerItem *self = CTK_MENU_TRACKER_ITEM (object)((((CtkMenuTrackerItem*) (void *) g_type_check_instance_cast ( (GTypeInstance*) ((object)), ((ctk_menu_tracker_item_get_type ())))))); |
159 | |
160 | switch (prop_id) |
161 | { |
162 | case PROP_IS_SEPARATOR: |
163 | g_value_set_boolean (value, ctk_menu_tracker_item_get_is_separator (self)); |
164 | break; |
165 | case PROP_LABEL: |
166 | g_value_set_string (value, ctk_menu_tracker_item_get_label (self)); |
167 | break; |
168 | case PROP_ICON: |
169 | g_value_take_object (value, ctk_menu_tracker_item_get_icon (self)); |
170 | break; |
171 | case PROP_VERB_ICON: |
172 | g_value_take_object (value, ctk_menu_tracker_item_get_verb_icon (self)); |
173 | break; |
174 | case PROP_SENSITIVE: |
175 | g_value_set_boolean (value, ctk_menu_tracker_item_get_sensitive (self)); |
176 | break; |
177 | case PROP_ROLE: |
178 | g_value_set_enum (value, ctk_menu_tracker_item_get_role (self)); |
179 | break; |
180 | case PROP_TOGGLED: |
181 | g_value_set_boolean (value, ctk_menu_tracker_item_get_toggled (self)); |
182 | break; |
183 | case PROP_ACCEL: |
184 | g_value_set_string (value, ctk_menu_tracker_item_get_accel (self)); |
185 | break; |
186 | case PROP_SUBMENU_SHOWN: |
187 | g_value_set_boolean (value, ctk_menu_tracker_item_get_submenu_shown (self)); |
188 | break; |
189 | case PROP_IS_VISIBLE: |
190 | g_value_set_boolean (value, ctk_menu_tracker_item_get_is_visible (self)); |
191 | break; |
192 | default: |
193 | 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'" , "ctkmenutrackeritem.c", 193, ("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); |
194 | break; |
195 | } |
196 | } |
197 | |
198 | static void |
199 | ctk_menu_tracker_item_finalize (GObject *object) |
200 | { |
201 | CtkMenuTrackerItem *self = CTK_MENU_TRACKER_ITEM (object)((((CtkMenuTrackerItem*) (void *) g_type_check_instance_cast ( (GTypeInstance*) ((object)), ((ctk_menu_tracker_item_get_type ())))))); |
202 | |
203 | g_free (self->action_namespace); |
204 | g_free (self->action_and_target); |
205 | |
206 | if (self->observable) |
207 | g_object_unref (self->observable); |
208 | |
209 | g_object_unref (self->item); |
210 | |
211 | G_OBJECT_CLASS (ctk_menu_tracker_item_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass *) ((ctk_menu_tracker_item_parent_class)), (((GType) ((20) << (2))))))))->finalize (object); |
212 | } |
213 | |
214 | static void |
215 | ctk_menu_tracker_item_init (CtkMenuTrackerItem * self G_GNUC_UNUSED__attribute__ ((__unused__))) |
216 | { |
217 | } |
218 | |
219 | static void |
220 | ctk_menu_tracker_item_class_init (CtkMenuTrackerItemClass *class) |
221 | { |
222 | class->get_property = ctk_menu_tracker_item_get_property; |
223 | class->finalize = ctk_menu_tracker_item_finalize; |
224 | |
225 | ctk_menu_tracker_item_pspecs[PROP_IS_SEPARATOR] = |
226 | g_param_spec_boolean ("is-separator", "", "", FALSE(0), G_PARAM_STATIC_STRINGS(G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB ) | G_PARAM_READABLE); |
227 | ctk_menu_tracker_item_pspecs[PROP_LABEL] = |
228 | g_param_spec_string ("label", "", "", NULL((void*)0), G_PARAM_STATIC_STRINGS(G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB ) | G_PARAM_READABLE); |
229 | ctk_menu_tracker_item_pspecs[PROP_ICON] = |
230 | g_param_spec_object ("icon", "", "", G_TYPE_ICON(g_icon_get_type ()), G_PARAM_STATIC_STRINGS(G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB ) | G_PARAM_READABLE); |
231 | ctk_menu_tracker_item_pspecs[PROP_VERB_ICON] = |
232 | g_param_spec_object ("verb-icon", "", "", G_TYPE_ICON(g_icon_get_type ()), G_PARAM_STATIC_STRINGS(G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB ) | G_PARAM_READABLE); |
233 | ctk_menu_tracker_item_pspecs[PROP_SENSITIVE] = |
234 | g_param_spec_boolean ("sensitive", "", "", FALSE(0), G_PARAM_STATIC_STRINGS(G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB ) | G_PARAM_READABLE); |
235 | ctk_menu_tracker_item_pspecs[PROP_ROLE] = |
236 | g_param_spec_enum ("role", "", "", |
237 | CTK_TYPE_MENU_TRACKER_ITEM_ROLE(ctk_menu_tracker_item_role_get_type ()), CTK_MENU_TRACKER_ITEM_ROLE_NORMAL, |
238 | G_PARAM_STATIC_STRINGS(G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB ) | G_PARAM_READABLE); |
239 | ctk_menu_tracker_item_pspecs[PROP_TOGGLED] = |
240 | g_param_spec_boolean ("toggled", "", "", FALSE(0), G_PARAM_STATIC_STRINGS(G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB ) | G_PARAM_READABLE); |
241 | ctk_menu_tracker_item_pspecs[PROP_ACCEL] = |
242 | g_param_spec_string ("accel", "", "", NULL((void*)0), G_PARAM_STATIC_STRINGS(G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB ) | G_PARAM_READABLE); |
243 | ctk_menu_tracker_item_pspecs[PROP_SUBMENU_SHOWN] = |
244 | g_param_spec_boolean ("submenu-shown", "", "", FALSE(0), G_PARAM_STATIC_STRINGS(G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB ) | G_PARAM_READABLE); |
245 | ctk_menu_tracker_item_pspecs[PROP_IS_VISIBLE] = |
246 | g_param_spec_boolean ("is-visible", "", "", FALSE(0), G_PARAM_STATIC_STRINGS(G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB ) | G_PARAM_READABLE); |
247 | |
248 | g_object_class_install_properties (class, N_PROPS, ctk_menu_tracker_item_pspecs); |
249 | } |
250 | |
251 | /* This syncs up the visibility for the hidden-when='' case. We call it |
252 | * from the action observer functions on changes to the action group and |
253 | * on initialisation (via the action observer functions that are invoked |
254 | * at that time). |
255 | */ |
256 | static void |
257 | ctk_menu_tracker_item_update_visibility (CtkMenuTrackerItem *self) |
258 | { |
259 | gboolean visible; |
260 | |
261 | switch (self->hidden_when) |
262 | { |
263 | case HIDDEN_NEVER0: |
264 | visible = TRUE(!(0)); |
265 | break; |
266 | |
267 | case HIDDEN_WHEN_MISSING1: |
268 | visible = self->can_activate; |
269 | break; |
270 | |
271 | case HIDDEN_WHEN_DISABLED2: |
272 | visible = self->sensitive; |
273 | break; |
274 | |
275 | case HIDDEN_WHEN_ALWAYS3: |
276 | visible = FALSE(0); |
277 | break; |
278 | |
279 | default: |
280 | g_assert_not_reached ()do { g_assertion_message_expr ("Ctk", "ctkmenutrackeritem.c", 280, ((const char*) (__func__)), ((void*)0)); } while (0); |
281 | } |
282 | |
283 | if (visible != self->is_visible) |
284 | { |
285 | self->is_visible = visible; |
286 | g_object_notify (G_OBJECT (self)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((self)), (((GType) ((20) << (2)))))))), "is-visible"); |
287 | } |
288 | } |
289 | |
290 | static void |
291 | ctk_menu_tracker_item_action_added (CtkActionObserver *observer, |
292 | CtkActionObservable *observable G_GNUC_UNUSED__attribute__ ((__unused__)), |
293 | const gchar *action_name, |
294 | const GVariantType *parameter_type, |
295 | gboolean enabled, |
296 | GVariant *state) |
297 | { |
298 | CtkMenuTrackerItem *self = CTK_MENU_TRACKER_ITEM (observer)((((CtkMenuTrackerItem*) (void *) g_type_check_instance_cast ( (GTypeInstance*) ((observer)), ((ctk_menu_tracker_item_get_type ())))))); |
299 | GVariant *action_target; |
300 | |
301 | CTK_NOTE(ACTIONS, g_message ("menutracker: action %s added", action_name))do { if ((ctk_get_debug_flags () & CTK_DEBUG_ACTIONS)) { g_message ("menutracker: action %s added", action_name); }; } while (0 ); |
302 | |
303 | action_target = g_menu_item_get_attribute_value (self->item, G_MENU_ATTRIBUTE_TARGET"target", NULL((void*)0)); |
304 | |
305 | self->can_activate = (action_target == NULL((void*)0) && parameter_type == NULL((void*)0)) || |
306 | (action_target != NULL((void*)0) && parameter_type != NULL((void*)0) && |
307 | g_variant_is_of_type (action_target, parameter_type)); |
308 | |
309 | if (!self->can_activate) |
310 | { |
311 | CTK_NOTE(ACTIONS, g_message ("menutracker: action %s can't be activated due to parameter type mismatch "do { if ((ctk_get_debug_flags () & CTK_DEBUG_ACTIONS)) { g_message ("menutracker: action %s can't be activated due to parameter type mismatch " "(parameter type %s, target type %s)", action_name, parameter_type ? g_variant_type_peek_string (parameter_type) : "NULL", action_target ? g_variant_get_type_string (action_target) : "NULL"); }; } while (0) |
312 | "(parameter type %s, target type %s)",do { if ((ctk_get_debug_flags () & CTK_DEBUG_ACTIONS)) { g_message ("menutracker: action %s can't be activated due to parameter type mismatch " "(parameter type %s, target type %s)", action_name, parameter_type ? g_variant_type_peek_string (parameter_type) : "NULL", action_target ? g_variant_get_type_string (action_target) : "NULL"); }; } while (0) |
313 | action_name,do { if ((ctk_get_debug_flags () & CTK_DEBUG_ACTIONS)) { g_message ("menutracker: action %s can't be activated due to parameter type mismatch " "(parameter type %s, target type %s)", action_name, parameter_type ? g_variant_type_peek_string (parameter_type) : "NULL", action_target ? g_variant_get_type_string (action_target) : "NULL"); }; } while (0) |
314 | parameter_type ? g_variant_type_peek_string (parameter_type) : "NULL",do { if ((ctk_get_debug_flags () & CTK_DEBUG_ACTIONS)) { g_message ("menutracker: action %s can't be activated due to parameter type mismatch " "(parameter type %s, target type %s)", action_name, parameter_type ? g_variant_type_peek_string (parameter_type) : "NULL", action_target ? g_variant_get_type_string (action_target) : "NULL"); }; } while (0) |
315 | action_target ? g_variant_get_type_string (action_target) : "NULL"))do { if ((ctk_get_debug_flags () & CTK_DEBUG_ACTIONS)) { g_message ("menutracker: action %s can't be activated due to parameter type mismatch " "(parameter type %s, target type %s)", action_name, parameter_type ? g_variant_type_peek_string (parameter_type) : "NULL", action_target ? g_variant_get_type_string (action_target) : "NULL"); }; } while (0); |
316 | |
317 | if (action_target) |
318 | g_variant_unref (action_target); |
319 | return; |
320 | } |
321 | |
322 | CTK_NOTE(ACTIONS, g_message ("menutracker: action %s can be activated", action_name))do { if ((ctk_get_debug_flags () & CTK_DEBUG_ACTIONS)) { g_message ("menutracker: action %s can be activated", action_name); }; } while (0); |
323 | |
324 | self->sensitive = enabled; |
325 | |
326 | CTK_NOTE(ACTIONS, g_message ("menutracker: action %s is %s", action_name, enabled ? "enabled" : "disabled"))do { if ((ctk_get_debug_flags () & CTK_DEBUG_ACTIONS)) { g_message ("menutracker: action %s is %s", action_name, enabled ? "enabled" : "disabled"); }; } while (0); |
327 | |
328 | if (action_target != NULL((void*)0) && state != NULL((void*)0)) |
329 | { |
330 | self->toggled = g_variant_equal (state, action_target); |
331 | self->role = CTK_MENU_TRACKER_ITEM_ROLE_RADIO; |
332 | } |
333 | |
334 | else if (state != NULL((void*)0) && g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN((const GVariantType *) "b"))) |
335 | { |
336 | self->toggled = g_variant_get_boolean (state); |
337 | self->role = CTK_MENU_TRACKER_ITEM_ROLE_CHECK; |
338 | } |
339 | |
340 | g_object_freeze_notify (G_OBJECT (self)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((self)), (((GType) ((20) << (2))))))))); |
341 | |
342 | if (self->sensitive) |
343 | g_object_notify_by_pspec (G_OBJECT (self)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((self)), (((GType) ((20) << (2)))))))), ctk_menu_tracker_item_pspecs[PROP_SENSITIVE]); |
344 | |
345 | if (self->toggled) |
346 | g_object_notify_by_pspec (G_OBJECT (self)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((self)), (((GType) ((20) << (2)))))))), ctk_menu_tracker_item_pspecs[PROP_TOGGLED]); |
347 | |
348 | if (self->role != CTK_MENU_TRACKER_ITEM_ROLE_NORMAL) |
349 | g_object_notify_by_pspec (G_OBJECT (self)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((self)), (((GType) ((20) << (2)))))))), ctk_menu_tracker_item_pspecs[PROP_ROLE]); |
350 | |
351 | g_object_thaw_notify (G_OBJECT (self)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((self)), (((GType) ((20) << (2))))))))); |
352 | |
353 | if (action_target) |
354 | g_variant_unref (action_target); |
355 | |
356 | /* In case of hidden-when='', we want to Wait until after refreshing |
357 | * all of the properties to emit the signal that will cause the |
358 | * tracker to expose us (to prevent too much thrashing). |
359 | */ |
360 | ctk_menu_tracker_item_update_visibility (self); |
361 | } |
362 | |
363 | static void |
364 | ctk_menu_tracker_item_action_enabled_changed (CtkActionObserver *observer, |
365 | CtkActionObservable *observable G_GNUC_UNUSED__attribute__ ((__unused__)), |
366 | const gchar *action_name, |
367 | gboolean enabled) |
368 | { |
369 | CtkMenuTrackerItem *self = CTK_MENU_TRACKER_ITEM (observer)((((CtkMenuTrackerItem*) (void *) g_type_check_instance_cast ( (GTypeInstance*) ((observer)), ((ctk_menu_tracker_item_get_type ())))))); |
370 | |
371 | CTK_NOTE(ACTIONS, g_message ("menutracker: action %s: enabled changed to %d", action_name, enabled))do { if ((ctk_get_debug_flags () & CTK_DEBUG_ACTIONS)) { g_message ("menutracker: action %s: enabled changed to %d", action_name , enabled); }; } while (0); |
372 | |
373 | if (!self->can_activate) |
374 | return; |
375 | |
376 | if (self->sensitive == enabled) |
377 | return; |
378 | |
379 | self->sensitive = enabled; |
380 | |
381 | g_object_notify_by_pspec (G_OBJECT (self)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((self)), (((GType) ((20) << (2)))))))), ctk_menu_tracker_item_pspecs[PROP_SENSITIVE]); |
382 | |
383 | ctk_menu_tracker_item_update_visibility (self); |
384 | } |
385 | |
386 | static void |
387 | ctk_menu_tracker_item_action_state_changed (CtkActionObserver *observer, |
388 | CtkActionObservable *observable G_GNUC_UNUSED__attribute__ ((__unused__)), |
389 | const gchar *action_name, |
390 | GVariant *state) |
391 | { |
392 | CtkMenuTrackerItem *self = CTK_MENU_TRACKER_ITEM (observer)((((CtkMenuTrackerItem*) (void *) g_type_check_instance_cast ( (GTypeInstance*) ((observer)), ((ctk_menu_tracker_item_get_type ())))))); |
393 | GVariant *action_target; |
394 | gboolean was_toggled; |
395 | |
396 | CTK_NOTE(ACTIONS, g_message ("menutracker: action %s: state changed", action_name))do { if ((ctk_get_debug_flags () & CTK_DEBUG_ACTIONS)) { g_message ("menutracker: action %s: state changed", action_name); }; } while (0); |
397 | |
398 | if (!self->can_activate) |
399 | return; |
400 | |
401 | action_target = g_menu_item_get_attribute_value (self->item, G_MENU_ATTRIBUTE_TARGET"target", NULL((void*)0)); |
402 | was_toggled = self->toggled; |
403 | |
404 | if (action_target) |
405 | { |
406 | self->toggled = g_variant_equal (state, action_target); |
407 | g_variant_unref (action_target); |
408 | } |
409 | |
410 | else if (g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN((const GVariantType *) "b"))) |
Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption | |
411 | self->toggled = g_variant_get_boolean (state); |
412 | |
413 | else |
414 | self->toggled = FALSE(0); |
415 | |
416 | if (self->toggled != was_toggled) |
417 | g_object_notify_by_pspec (G_OBJECT (self)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((self)), (((GType) ((20) << (2)))))))), ctk_menu_tracker_item_pspecs[PROP_TOGGLED]); |
418 | } |
419 | |
420 | static void |
421 | ctk_menu_tracker_item_action_removed (CtkActionObserver *observer, |
422 | CtkActionObservable *observable G_GNUC_UNUSED__attribute__ ((__unused__)), |
423 | const gchar *action_name) |
424 | { |
425 | CtkMenuTrackerItem *self = CTK_MENU_TRACKER_ITEM (observer)((((CtkMenuTrackerItem*) (void *) g_type_check_instance_cast ( (GTypeInstance*) ((observer)), ((ctk_menu_tracker_item_get_type ())))))); |
426 | gboolean was_sensitive, was_toggled; |
427 | CtkMenuTrackerItemRole old_role; |
428 | |
429 | CTK_NOTE(ACTIONS, g_message ("menutracker: action %s was removed", action_name))do { if ((ctk_get_debug_flags () & CTK_DEBUG_ACTIONS)) { g_message ("menutracker: action %s was removed", action_name); }; } while (0); |
430 | |
431 | if (!self->can_activate) |
432 | return; |
433 | |
434 | was_sensitive = self->sensitive; |
435 | was_toggled = self->toggled; |
436 | old_role = self->role; |
437 | |
438 | self->can_activate = FALSE(0); |
439 | self->sensitive = FALSE(0); |
440 | self->toggled = FALSE(0); |
441 | self->role = CTK_MENU_TRACKER_ITEM_ROLE_NORMAL; |
442 | |
443 | /* Backwards from adding: we want to remove ourselves from the menu |
444 | * -before- thrashing the properties. |
445 | */ |
446 | ctk_menu_tracker_item_update_visibility (self); |
447 | |
448 | g_object_freeze_notify (G_OBJECT (self)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((self)), (((GType) ((20) << (2))))))))); |
449 | |
450 | if (was_sensitive) |
451 | g_object_notify_by_pspec (G_OBJECT (self)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((self)), (((GType) ((20) << (2)))))))), ctk_menu_tracker_item_pspecs[PROP_SENSITIVE]); |
452 | |
453 | if (was_toggled) |
454 | g_object_notify_by_pspec (G_OBJECT (self)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((self)), (((GType) ((20) << (2)))))))), ctk_menu_tracker_item_pspecs[PROP_TOGGLED]); |
455 | |
456 | if (old_role != CTK_MENU_TRACKER_ITEM_ROLE_NORMAL) |
457 | g_object_notify_by_pspec (G_OBJECT (self)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((self)), (((GType) ((20) << (2)))))))), ctk_menu_tracker_item_pspecs[PROP_ROLE]); |
458 | |
459 | g_object_thaw_notify (G_OBJECT (self)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((self)), (((GType) ((20) << (2))))))))); |
460 | } |
461 | |
462 | static void |
463 | ctk_menu_tracker_item_primary_accel_changed (CtkActionObserver *observer, |
464 | CtkActionObservable *observable G_GNUC_UNUSED__attribute__ ((__unused__)), |
465 | const gchar *action_name G_GNUC_UNUSED__attribute__ ((__unused__)), |
466 | const gchar *action_and_target) |
467 | { |
468 | CtkMenuTrackerItem *self = CTK_MENU_TRACKER_ITEM (observer)((((CtkMenuTrackerItem*) (void *) g_type_check_instance_cast ( (GTypeInstance*) ((observer)), ((ctk_menu_tracker_item_get_type ())))))); |
469 | |
470 | if (g_str_equal (action_and_target, self->action_and_target)(strcmp ((const char *) (action_and_target), (const char *) ( self->action_and_target)) == 0)) |
471 | g_object_notify_by_pspec (G_OBJECT (self)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((self)), (((GType) ((20) << (2)))))))), ctk_menu_tracker_item_pspecs[PROP_ACCEL]); |
472 | } |
473 | |
474 | static void |
475 | ctk_menu_tracker_item_init_observer_iface (CtkActionObserverInterface *iface) |
476 | { |
477 | iface->action_added = ctk_menu_tracker_item_action_added; |
478 | iface->action_enabled_changed = ctk_menu_tracker_item_action_enabled_changed; |
479 | iface->action_state_changed = ctk_menu_tracker_item_action_state_changed; |
480 | iface->action_removed = ctk_menu_tracker_item_action_removed; |
481 | iface->primary_accel_changed = ctk_menu_tracker_item_primary_accel_changed; |
482 | } |
483 | |
484 | CtkMenuTrackerItem * |
485 | _ctk_menu_tracker_item_new (CtkActionObservable *observable, |
486 | GMenuModel *model, |
487 | gint item_index, |
488 | gboolean mac_os_mode, |
489 | const gchar *action_namespace, |
490 | gboolean is_separator) |
491 | { |
492 | CtkMenuTrackerItem *self; |
493 | const gchar *action_name; |
494 | const gchar *hidden_when; |
495 | |
496 | g_return_val_if_fail (CTK_IS_ACTION_OBSERVABLE (observable), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((observable)); GType __t = ((ctk_action_observable_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_OBSERVABLE (observable)") ; return (((void*)0)); } } while (0); |
497 | g_return_val_if_fail (G_IS_MENU_MODEL (model), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((model)); GType __t = ((g_menu_model_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__ )), "G_IS_MENU_MODEL (model)"); return (((void*)0)); } } while (0); |
498 | |
499 | self = g_object_new (CTK_TYPE_MENU_TRACKER_ITEM(ctk_menu_tracker_item_get_type ()), NULL((void*)0)); |
500 | self->item = g_menu_item_new_from_model (model, item_index); |
501 | self->action_namespace = g_strdup (action_namespace)g_strdup_inline (action_namespace); |
502 | self->observable = g_object_ref (observable)((__typeof__ (observable)) (g_object_ref) (observable)); |
503 | self->is_separator = is_separator; |
504 | |
505 | if (!is_separator && g_menu_item_get_attribute (self->item, "hidden-when", "&s", &hidden_when)) |
506 | { |
507 | if (g_str_equal (hidden_when, "action-disabled")(strcmp ((const char *) (hidden_when), (const char *) ("action-disabled" )) == 0)) |
508 | self->hidden_when = HIDDEN_WHEN_DISABLED2; |
509 | else if (g_str_equal (hidden_when, "action-missing")(strcmp ((const char *) (hidden_when), (const char *) ("action-missing" )) == 0)) |
510 | self->hidden_when = HIDDEN_WHEN_MISSING1; |
511 | else if (mac_os_mode && g_str_equal (hidden_when, "macos-menubar")(strcmp ((const char *) (hidden_when), (const char *) ("macos-menubar" )) == 0)) |
512 | self->hidden_when = HIDDEN_WHEN_ALWAYS3; |
513 | |
514 | /* Ignore other values -- this code may be running in context of a |
515 | * desktop shell or the like and should not spew criticals due to |
516 | * application bugs... |
517 | * |
518 | * Note: if we just set a hidden-when state, but don't get the |
519 | * action_name below then our visibility will be FALSE forever. |
520 | * That's to be expected since the action is missing... |
521 | */ |
522 | } |
523 | |
524 | if (!is_separator && g_menu_item_get_attribute (self->item, "action", "&s", &action_name)) |
525 | { |
526 | GActionGroup *group = G_ACTION_GROUP (observable)((((GActionGroup*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((observable)), ((g_action_group_get_type ())))))); |
527 | const GVariantType *parameter_type; |
528 | GVariant *target; |
529 | gboolean enabled; |
530 | GVariant *state; |
531 | gboolean found; |
532 | |
533 | target = g_menu_item_get_attribute_value (self->item, "target", NULL((void*)0)); |
534 | |
535 | self->action_and_target = ctk_print_action_and_target (action_namespace, action_name, target); |
536 | |
537 | if (target) |
538 | g_variant_unref (target); |
539 | |
540 | action_name = strrchr (self->action_and_target, '|') + 1; |
541 | |
542 | CTK_NOTE(ACTIONS,do { if ((ctk_get_debug_flags () & CTK_DEBUG_ACTIONS)) { if (!strchr (action_name, '.')) g_message ("menutracker: action name %s doesn't look like 'app.' or 'win.'; " "it is unlikely to work", action_name); }; } while (0) |
543 | if (!strchr (action_name, '.'))do { if ((ctk_get_debug_flags () & CTK_DEBUG_ACTIONS)) { if (!strchr (action_name, '.')) g_message ("menutracker: action name %s doesn't look like 'app.' or 'win.'; " "it is unlikely to work", action_name); }; } while (0) |
544 | g_message ("menutracker: action name %s doesn't look like 'app.' or 'win.'; "do { if ((ctk_get_debug_flags () & CTK_DEBUG_ACTIONS)) { if (!strchr (action_name, '.')) g_message ("menutracker: action name %s doesn't look like 'app.' or 'win.'; " "it is unlikely to work", action_name); }; } while (0) |
545 | "it is unlikely to work", action_name))do { if ((ctk_get_debug_flags () & CTK_DEBUG_ACTIONS)) { if (!strchr (action_name, '.')) g_message ("menutracker: action name %s doesn't look like 'app.' or 'win.'; " "it is unlikely to work", action_name); }; } while (0); |
546 | |
547 | state = NULL((void*)0); |
548 | |
549 | ctk_action_observable_register_observer (self->observable, action_name, CTK_ACTION_OBSERVER (self)((((CtkActionObserver*) (void *) g_type_check_instance_cast ( (GTypeInstance*) ((self)), ((ctk_action_observer_get_type ()) )))))); |
550 | found = g_action_group_query_action (group, action_name, &enabled, ¶meter_type, NULL((void*)0), NULL((void*)0), &state); |
551 | |
552 | if (found) |
553 | { |
554 | CTK_NOTE(ACTIONS, g_message ("menutracker: action %s existed from the start", action_name))do { if ((ctk_get_debug_flags () & CTK_DEBUG_ACTIONS)) { g_message ("menutracker: action %s existed from the start", action_name ); }; } while (0); |
555 | ctk_menu_tracker_item_action_added (CTK_ACTION_OBSERVER (self)((((CtkActionObserver*) (void *) g_type_check_instance_cast ( (GTypeInstance*) ((self)), ((ctk_action_observer_get_type ()) ))))), observable, NULL((void*)0), parameter_type, enabled, state); |
556 | } |
557 | else |
558 | { |
559 | CTK_NOTE(ACTIONS, g_message ("menutracker: action %s missing from the start", action_name))do { if ((ctk_get_debug_flags () & CTK_DEBUG_ACTIONS)) { g_message ("menutracker: action %s missing from the start", action_name ); }; } while (0); |
560 | ctk_menu_tracker_item_update_visibility (self); |
561 | } |
562 | |
563 | if (state) |
564 | g_variant_unref (state); |
565 | } |
566 | else |
567 | { |
568 | ctk_menu_tracker_item_update_visibility (self); |
569 | self->sensitive = TRUE(!(0)); |
570 | } |
571 | |
572 | return self; |
573 | } |
574 | |
575 | CtkActionObservable * |
576 | _ctk_menu_tracker_item_get_observable (CtkMenuTrackerItem *self) |
577 | { |
578 | return self->observable; |
579 | } |
580 | |
581 | /*< private > |
582 | * ctk_menu_tracker_item_get_is_separator: |
583 | * @self: A #CtkMenuTrackerItem instance |
584 | * |
585 | * Returns: whether the menu item is a separator. If so, only |
586 | * certain properties may need to be obeyed. See the documentation |
587 | * for #CtkMenuTrackerItem. |
588 | */ |
589 | gboolean |
590 | ctk_menu_tracker_item_get_is_separator (CtkMenuTrackerItem *self) |
591 | { |
592 | return self->is_separator; |
593 | } |
594 | |
595 | /*< private > |
596 | * ctk_menu_tracker_item_get_has_submenu: |
597 | * @self: A #CtkMenuTrackerItem instance |
598 | * |
599 | * Returns: whether the menu item has a submenu. If so, only |
600 | * certain properties may need to be obeyed. See the documentation |
601 | * for #CtkMenuTrackerItem. |
602 | */ |
603 | gboolean |
604 | ctk_menu_tracker_item_get_has_link (CtkMenuTrackerItem *self, |
605 | const gchar *link_name) |
606 | { |
607 | GMenuModel *link; |
608 | |
609 | link = g_menu_item_get_link (self->item, link_name); |
610 | |
611 | if (link) |
612 | { |
613 | g_object_unref (link); |
614 | return TRUE(!(0)); |
615 | } |
616 | else |
617 | return FALSE(0); |
618 | } |
619 | |
620 | const gchar * |
621 | ctk_menu_tracker_item_get_label (CtkMenuTrackerItem *self) |
622 | { |
623 | const gchar *label = NULL((void*)0); |
624 | |
625 | g_menu_item_get_attribute (self->item, G_MENU_ATTRIBUTE_LABEL"label", "&s", &label); |
626 | |
627 | return label; |
628 | } |
629 | |
630 | /*< private > |
631 | * ctk_menu_tracker_item_get_icon: |
632 | * |
633 | * Returns: (transfer full): |
634 | */ |
635 | GIcon * |
636 | ctk_menu_tracker_item_get_icon (CtkMenuTrackerItem *self) |
637 | { |
638 | GVariant *icon_data; |
639 | GIcon *icon; |
640 | |
641 | icon_data = g_menu_item_get_attribute_value (self->item, "icon", NULL((void*)0)); |
642 | |
643 | if (icon_data == NULL((void*)0)) |
644 | return NULL((void*)0); |
645 | |
646 | icon = g_icon_deserialize (icon_data); |
647 | g_variant_unref (icon_data); |
648 | |
649 | return icon; |
650 | } |
651 | |
652 | /*< private > |
653 | * ctk_menu_tracker_item_get_verb_icon: |
654 | * |
655 | * Returns: (transfer full): |
656 | */ |
657 | GIcon * |
658 | ctk_menu_tracker_item_get_verb_icon (CtkMenuTrackerItem *self) |
659 | { |
660 | GVariant *icon_data; |
661 | GIcon *icon; |
662 | |
663 | icon_data = g_menu_item_get_attribute_value (self->item, "verb-icon", NULL((void*)0)); |
664 | |
665 | if (icon_data == NULL((void*)0)) |
666 | return NULL((void*)0); |
667 | |
668 | icon = g_icon_deserialize (icon_data); |
669 | g_variant_unref (icon_data); |
670 | |
671 | return icon; |
672 | } |
673 | |
674 | gboolean |
675 | ctk_menu_tracker_item_get_sensitive (CtkMenuTrackerItem *self) |
676 | { |
677 | return self->sensitive; |
678 | } |
679 | |
680 | CtkMenuTrackerItemRole |
681 | ctk_menu_tracker_item_get_role (CtkMenuTrackerItem *self) |
682 | { |
683 | return self->role; |
684 | } |
685 | |
686 | gboolean |
687 | ctk_menu_tracker_item_get_toggled (CtkMenuTrackerItem *self) |
688 | { |
689 | return self->toggled; |
690 | } |
691 | |
692 | const gchar * |
693 | ctk_menu_tracker_item_get_accel (CtkMenuTrackerItem *self) |
694 | { |
695 | const gchar *accel; |
696 | |
697 | if (!self->action_and_target) |
698 | return NULL((void*)0); |
699 | |
700 | if (g_menu_item_get_attribute (self->item, "accel", "&s", &accel)) |
701 | return accel; |
702 | |
703 | if (!CTK_IS_ACTION_MUXER (self->observable)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) ( (self->observable)); GType __t = ((ctk_action_muxer_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; }))))) |
704 | return NULL((void*)0); |
705 | |
706 | return ctk_action_muxer_get_primary_accel (CTK_ACTION_MUXER (self->observable)((((CtkActionMuxer*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((self->observable)), ((ctk_action_muxer_get_type ()))) ))), self->action_and_target); |
707 | } |
708 | |
709 | const gchar * |
710 | ctk_menu_tracker_item_get_special (CtkMenuTrackerItem *self) |
711 | { |
712 | const gchar *special = NULL((void*)0); |
713 | |
714 | g_menu_item_get_attribute (self->item, "x-ctk-private-special", "&s", &special); |
715 | |
716 | return special; |
717 | } |
718 | |
719 | const gchar * |
720 | ctk_menu_tracker_item_get_display_hint (CtkMenuTrackerItem *self) |
721 | { |
722 | const gchar *display_hint = NULL((void*)0); |
723 | |
724 | g_menu_item_get_attribute (self->item, "display-hint", "&s", &display_hint); |
725 | |
726 | return display_hint; |
727 | } |
728 | |
729 | const gchar * |
730 | ctk_menu_tracker_item_get_text_direction (CtkMenuTrackerItem *self) |
731 | { |
732 | const gchar *text_direction = NULL((void*)0); |
733 | |
734 | g_menu_item_get_attribute (self->item, "text-direction", "&s", &text_direction); |
735 | |
736 | return text_direction; |
737 | } |
738 | |
739 | GMenuModel * |
740 | _ctk_menu_tracker_item_get_link (CtkMenuTrackerItem *self, |
741 | const gchar *link_name) |
742 | { |
743 | return g_menu_item_get_link (self->item, link_name); |
744 | } |
745 | |
746 | gchar * |
747 | _ctk_menu_tracker_item_get_link_namespace (CtkMenuTrackerItem *self) |
748 | { |
749 | const gchar *namespace; |
750 | |
751 | if (g_menu_item_get_attribute (self->item, "action-namespace", "&s", &namespace)) |
752 | { |
753 | if (self->action_namespace) |
754 | return g_strjoin (".", self->action_namespace, namespace, NULL((void*)0)); |
755 | else |
756 | return g_strdup (namespace)g_strdup_inline (namespace); |
757 | } |
758 | else |
759 | return g_strdup (self->action_namespace)g_strdup_inline (self->action_namespace); |
760 | } |
761 | |
762 | gboolean |
763 | ctk_menu_tracker_item_get_should_request_show (CtkMenuTrackerItem *self) |
764 | { |
765 | return g_menu_item_get_attribute (self->item, "submenu-action", "&s", NULL((void*)0)); |
766 | } |
767 | |
768 | gboolean |
769 | ctk_menu_tracker_item_get_submenu_shown (CtkMenuTrackerItem *self) |
770 | { |
771 | return self->submenu_shown; |
772 | } |
773 | |
774 | static void |
775 | ctk_menu_tracker_item_set_submenu_shown (CtkMenuTrackerItem *self, |
776 | gboolean submenu_shown) |
777 | { |
778 | if (submenu_shown == self->submenu_shown) |
779 | return; |
780 | |
781 | self->submenu_shown = submenu_shown; |
782 | g_object_notify_by_pspec (G_OBJECT (self)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((self)), (((GType) ((20) << (2)))))))), ctk_menu_tracker_item_pspecs[PROP_SUBMENU_SHOWN]); |
783 | } |
784 | |
785 | void |
786 | ctk_menu_tracker_item_activated (CtkMenuTrackerItem *self) |
787 | { |
788 | const gchar *action_name; |
789 | GVariant *action_target; |
790 | |
791 | g_return_if_fail (CTK_IS_MENU_TRACKER_ITEM (self))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((self)); GType __t = ((ctk_menu_tracker_item_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_MENU_TRACKER_ITEM (self)"); return ; } } while (0); |
792 | |
793 | if (!self->can_activate) |
794 | return; |
795 | |
796 | action_name = strrchr (self->action_and_target, '|') + 1; |
797 | action_target = g_menu_item_get_attribute_value (self->item, G_MENU_ATTRIBUTE_TARGET"target", NULL((void*)0)); |
798 | |
799 | g_action_group_activate_action (G_ACTION_GROUP (self->observable)((((GActionGroup*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((self->observable)), ((g_action_group_get_type ()))))) ), action_name, action_target); |
800 | |
801 | if (action_target) |
802 | g_variant_unref (action_target); |
803 | } |
804 | |
805 | typedef struct |
806 | { |
807 | CtkMenuTrackerItem *item; |
808 | gchar *submenu_action; |
809 | gboolean first_time; |
810 | } CtkMenuTrackerOpener; |
811 | |
812 | static void |
813 | ctk_menu_tracker_opener_update (CtkMenuTrackerOpener *opener) |
814 | { |
815 | GActionGroup *group = G_ACTION_GROUP (opener->item->observable)((((GActionGroup*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((opener->item->observable)), ((g_action_group_get_type ())))))); |
816 | gboolean is_open = TRUE(!(0)); |
817 | |
818 | /* We consider the menu as being "open" if the action does not exist |
819 | * or if there is another problem (no state, wrong state type, etc.). |
820 | * If the action exists, with the correct state then we consider it |
821 | * open if we have ever seen this state equal to TRUE. |
822 | * |
823 | * In the event that we see the state equal to FALSE, we force it back |
824 | * to TRUE. We do not signal that the menu was closed because this is |
825 | * likely to create UI thrashing. |
826 | * |
827 | * The only way the menu can have a true-to-false submenu-shown |
828 | * transition is if the user calls _request_submenu_shown (FALSE). |
829 | * That is handled in _free() below. |
830 | */ |
831 | |
832 | if (g_action_group_has_action (group, opener->submenu_action)) |
833 | { |
834 | GVariant *state = g_action_group_get_action_state (group, opener->submenu_action); |
835 | |
836 | if (state) |
837 | { |
838 | if (g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN((const GVariantType *) "b"))) |
839 | is_open = g_variant_get_boolean (state); |
840 | g_variant_unref (state); |
841 | } |
842 | } |
843 | |
844 | /* If it is already open, signal that. |
845 | * |
846 | * If it is not open, ask it to open. |
847 | */ |
848 | if (is_open) |
849 | ctk_menu_tracker_item_set_submenu_shown (opener->item, TRUE(!(0))); |
850 | |
851 | if (!is_open || opener->first_time) |
852 | { |
853 | g_action_group_change_action_state (group, opener->submenu_action, g_variant_new_boolean (TRUE(!(0)))); |
854 | opener->first_time = FALSE(0); |
855 | } |
856 | } |
857 | |
858 | static void |
859 | ctk_menu_tracker_opener_added (GActionGroup *group G_GNUC_UNUSED__attribute__ ((__unused__)), |
860 | const gchar *action_name, |
861 | gpointer user_data) |
862 | { |
863 | CtkMenuTrackerOpener *opener = user_data; |
864 | |
865 | if (g_str_equal (action_name, opener->submenu_action)(strcmp ((const char *) (action_name), (const char *) (opener ->submenu_action)) == 0)) |
866 | ctk_menu_tracker_opener_update (opener); |
867 | } |
868 | |
869 | static void |
870 | ctk_menu_tracker_opener_removed (GActionGroup *action_group G_GNUC_UNUSED__attribute__ ((__unused__)), |
871 | const gchar *action_name, |
872 | gpointer user_data) |
873 | { |
874 | CtkMenuTrackerOpener *opener = user_data; |
875 | |
876 | if (g_str_equal (action_name, opener->submenu_action)(strcmp ((const char *) (action_name), (const char *) (opener ->submenu_action)) == 0)) |
877 | ctk_menu_tracker_opener_update (opener); |
878 | } |
879 | |
880 | static void |
881 | ctk_menu_tracker_opener_changed (GActionGroup *action_group G_GNUC_UNUSED__attribute__ ((__unused__)), |
882 | const gchar *action_name, |
883 | GVariant *new_state G_GNUC_UNUSED__attribute__ ((__unused__)), |
884 | gpointer user_data) |
885 | { |
886 | CtkMenuTrackerOpener *opener = user_data; |
887 | |
888 | if (g_str_equal (action_name, opener->submenu_action)(strcmp ((const char *) (action_name), (const char *) (opener ->submenu_action)) == 0)) |
889 | ctk_menu_tracker_opener_update (opener); |
890 | } |
891 | |
892 | static void |
893 | ctk_menu_tracker_opener_free (gpointer data) |
894 | { |
895 | CtkMenuTrackerOpener *opener = data; |
896 | |
897 | g_signal_handlers_disconnect_by_func (opener->item->observable, ctk_menu_tracker_opener_added, opener)g_signal_handlers_disconnect_matched ((opener->item->observable ), (GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA ), 0, 0, ((void*)0), (ctk_menu_tracker_opener_added), (opener )); |
898 | g_signal_handlers_disconnect_by_func (opener->item->observable, ctk_menu_tracker_opener_removed, opener)g_signal_handlers_disconnect_matched ((opener->item->observable ), (GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA ), 0, 0, ((void*)0), (ctk_menu_tracker_opener_removed), (opener )); |
899 | g_signal_handlers_disconnect_by_func (opener->item->observable, ctk_menu_tracker_opener_changed, opener)g_signal_handlers_disconnect_matched ((opener->item->observable ), (GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA ), 0, 0, ((void*)0), (ctk_menu_tracker_opener_changed), (opener )); |
900 | |
901 | g_action_group_change_action_state (G_ACTION_GROUP (opener->item->observable)((((GActionGroup*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((opener->item->observable)), ((g_action_group_get_type ())))))), |
902 | opener->submenu_action, |
903 | g_variant_new_boolean (FALSE(0))); |
904 | |
905 | ctk_menu_tracker_item_set_submenu_shown (opener->item, FALSE(0)); |
906 | |
907 | g_free (opener->submenu_action); |
908 | |
909 | g_slice_free (CtkMenuTrackerOpener, opener)do { if (1) g_slice_free1 (sizeof (CtkMenuTrackerOpener), (opener )); else (void) ((CtkMenuTrackerOpener*) 0 == (opener)); } while (0); |
910 | } |
911 | |
912 | static CtkMenuTrackerOpener * |
913 | ctk_menu_tracker_opener_new (CtkMenuTrackerItem *item, |
914 | const gchar *submenu_action) |
915 | { |
916 | CtkMenuTrackerOpener *opener; |
917 | |
918 | opener = g_slice_new (CtkMenuTrackerOpener)((CtkMenuTrackerOpener*) g_slice_alloc (sizeof (CtkMenuTrackerOpener ))); |
919 | opener->first_time = TRUE(!(0)); |
920 | opener->item = item; |
921 | |
922 | if (item->action_namespace) |
923 | opener->submenu_action = g_strjoin (".", item->action_namespace, submenu_action, NULL((void*)0)); |
924 | else |
925 | opener->submenu_action = g_strdup (submenu_action)g_strdup_inline (submenu_action); |
926 | |
927 | g_signal_connect (item->observable, "action-added", G_CALLBACK (ctk_menu_tracker_opener_added), opener)g_signal_connect_data ((item->observable), ("action-added" ), (((GCallback) (ctk_menu_tracker_opener_added))), (opener), ((void*)0), (GConnectFlags) 0); |
928 | g_signal_connect (item->observable, "action-removed", G_CALLBACK (ctk_menu_tracker_opener_removed), opener)g_signal_connect_data ((item->observable), ("action-removed" ), (((GCallback) (ctk_menu_tracker_opener_removed))), (opener ), ((void*)0), (GConnectFlags) 0); |
929 | g_signal_connect (item->observable, "action-state-changed", G_CALLBACK (ctk_menu_tracker_opener_changed), opener)g_signal_connect_data ((item->observable), ("action-state-changed" ), (((GCallback) (ctk_menu_tracker_opener_changed))), (opener ), ((void*)0), (GConnectFlags) 0); |
930 | |
931 | ctk_menu_tracker_opener_update (opener); |
932 | |
933 | return opener; |
934 | } |
935 | |
936 | void |
937 | ctk_menu_tracker_item_request_submenu_shown (CtkMenuTrackerItem *self, |
938 | gboolean shown) |
939 | { |
940 | const gchar *submenu_action; |
941 | gboolean has_submenu_action; |
942 | |
943 | if (shown == self->submenu_requested) |
944 | return; |
945 | |
946 | has_submenu_action = g_menu_item_get_attribute (self->item, "submenu-action", "&s", &submenu_action); |
947 | |
948 | self->submenu_requested = shown; |
949 | |
950 | /* If we have a submenu action, start a submenu opener and wait |
951 | * for the reply from the client. Otherwise, simply open the |
952 | * submenu immediately. |
953 | */ |
954 | if (has_submenu_action) |
955 | { |
956 | if (shown) |
957 | g_object_set_data_full (G_OBJECT (self)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((self)), (((GType) ((20) << (2)))))))), "submenu-opener", |
958 | ctk_menu_tracker_opener_new (self, submenu_action), |
959 | ctk_menu_tracker_opener_free); |
960 | else |
961 | g_object_set_data (G_OBJECT (self)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((self)), (((GType) ((20) << (2)))))))), "submenu-opener", NULL((void*)0)); |
962 | } |
963 | else |
964 | ctk_menu_tracker_item_set_submenu_shown (self, shown); |
965 | } |
966 | |
967 | /** |
968 | * ctk_menu_tracker_item_get_is_visible: |
969 | * @self: A #CtkMenuTrackerItem instance |
970 | * |
971 | * Don't use this unless you're tracking items for yourself -- normally |
972 | * the tracker will emit add/remove automatically when this changes. |
973 | * |
974 | * Returns: if the item should currently be shown |
975 | */ |
976 | gboolean |
977 | ctk_menu_tracker_item_get_is_visible (CtkMenuTrackerItem *self) |
978 | { |
979 | return self->is_visible; |
980 | } |
981 | |
982 | /** |
983 | * ctk_menu_tracker_item_may_disappear: |
984 | * @self: A #CtkMenuTrackerItem instance |
985 | * |
986 | * Returns: if the item may disappear (ie: is-visible property may change) |
987 | */ |
988 | gboolean |
989 | ctk_menu_tracker_item_may_disappear (CtkMenuTrackerItem *self) |
990 | { |
991 | return self->hidden_when != HIDDEN_NEVER0; |
992 | } |