Bug Summary

File:ctk/ctkemojichooser.c
Warning:line 189, column 37
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 ctkemojichooser.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/rootdir/ctk -fcoverage-compilation-dir=/rootdir/ctk -resource-dir /usr/lib/llvm-21/lib/clang/21 -D HAVE_CONFIG_H -I . -I .. -D G_LOG_DOMAIN="Ctk" -D G_LOG_USE_STRUCTURED=1 -D CTK_VERSION="3.26.0" -D CTK_BINARY_VERSION="3.0.0" -D CTK_COMPILATION -D CTK_PRINT_BACKEND_ENABLE_UNSUPPORTED -D CTK_LIBDIR="/usr/lib" -D CTK_LOCALEDIR="/usr/share/locale" -D CTK_DATADIR="/usr/share" -D CTK_DATA_PREFIX="/usr" -D CTK_SYSCONFDIR="/usr/etc" -D CTK_HOST="x86_64-pc-linux-gnu" -D CTK_PRINT_BACKENDS="file,cups" -D X11_DATA_PREFIX="/usr" -D ISO_CODES_PREFIX="" -I .. -I ../ctk -I .. -I ../cdk -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -D G_ENABLE_DEBUG -D G_DISABLE_CAST_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/cairo -I /usr/local/include/cdk-pixbuf-2.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/atk-1.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/fribidi -I /usr/include/pixman-1 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/gio-unix-2.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -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/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 -D PIC -internal-isystem /usr/lib/llvm-21/lib/clang/21/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/15/../../../../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 -fvisibility=hidden -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -analyzer-checker deadcode.DeadStores -analyzer-checker security.ArrayBound -analyzer-checker unix.cstring.NotNullTerminated -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -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/2026-06-09-180917-46040-1 -x c ctkemojichooser.c
1/* ctkemojichooser.c: An Emoji chooser widget
2 * Copyright 2017, Red Hat, Inc.
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 License, 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
18#include "config.h"
19
20#include "ctkemojichooser.h"
21
22#include "ctkadjustmentprivate.h"
23#include "ctkbox.h"
24#include "ctkbutton.h"
25#include "ctkcssprovider.h"
26#include "ctkentry.h"
27#include "ctkflowbox.h"
28#include "ctkstack.h"
29#include "ctklabel.h"
30#include "ctkgesturelongpress.h"
31#include "ctkgesturemultipress.h"
32#include "ctkpopover.h"
33#include "ctkscrolledwindow.h"
34#include "ctkeventbox.h"
35#include "ctkintl.h"
36#include "ctkprivate.h"
37
38#define BOX_SPACE6 6
39
40typedef struct {
41 CtkWidget *box;
42 CtkWidget *heading;
43 CtkWidget *button;
44 const char *first;
45 gunichar label;
46 gboolean empty;
47} EmojiSection;
48
49struct _CtkEmojiChooser
50{
51 CtkPopover parent_instance;
52
53 CtkWidget *search_entry;
54 CtkWidget *stack;
55 CtkWidget *scrolled_window;
56
57 int emoji_max_width;
58
59 EmojiSection recent;
60 EmojiSection people;
61 EmojiSection body;
62 EmojiSection nature;
63 EmojiSection food;
64 EmojiSection travel;
65 EmojiSection activities;
66 EmojiSection objects;
67 EmojiSection symbols;
68 EmojiSection flags;
69
70 CtkGesture *recent_long_press;
71 CtkGesture *recent_multi_press;
72 CtkGesture *people_long_press;
73 CtkGesture *people_multi_press;
74 CtkGesture *body_long_press;
75 CtkGesture *body_multi_press;
76
77 GVariant *data;
78 CtkWidget *box;
79 GVariantIter *iter;
80 guint populate_idle;
81
82 GSettings *settings;
83};
84
85struct _CtkEmojiChooserClass {
86 CtkPopoverClass parent_class;
87};
88
89enum {
90 EMOJI_PICKED,
91 LAST_SIGNAL
92};
93
94static int signals[LAST_SIGNAL];
95
96G_DEFINE_TYPE (CtkEmojiChooser, ctk_emoji_chooser, CTK_TYPE_POPOVER)static void ctk_emoji_chooser_init (CtkEmojiChooser *self); static
void ctk_emoji_chooser_class_init (CtkEmojiChooserClass *klass
); static GType ctk_emoji_chooser_get_type_once (void); static
gpointer ctk_emoji_chooser_parent_class = ((void*)0); static
gint CtkEmojiChooser_private_offset; static void ctk_emoji_chooser_class_intern_init
(gpointer klass) { ctk_emoji_chooser_parent_class = g_type_class_peek_parent
(klass); if (CtkEmojiChooser_private_offset != 0) g_type_class_adjust_private_offset
(klass, &CtkEmojiChooser_private_offset); ctk_emoji_chooser_class_init
((CtkEmojiChooserClass*) klass); } __attribute__ ((__unused__
)) static inline gpointer ctk_emoji_chooser_get_instance_private
(CtkEmojiChooser *self) { return (((gpointer) ((guint8*) (self
) + (glong) (CtkEmojiChooser_private_offset)))); } GType ctk_emoji_chooser_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_emoji_chooser_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_emoji_chooser_get_type_once (
void) { GType g_define_type_id = g_type_register_static_simple
((ctk_popover_get_type ()), g_intern_static_string ("CtkEmojiChooser"
), sizeof (CtkEmojiChooserClass), (GClassInitFunc)(void (*)(void
)) ctk_emoji_chooser_class_intern_init, sizeof (CtkEmojiChooser
), (GInstanceInitFunc)(void (*)(void)) ctk_emoji_chooser_init
, (GTypeFlags) 0); { {{};} } return g_define_type_id; }
97
98static void
99ctk_emoji_chooser_finalize (GObject *object)
100{
101 CtkEmojiChooser *chooser = CTK_EMOJI_CHOOSER (object)((((CtkEmojiChooser*) (void *) ((object)))));
102
103 if (chooser->populate_idle)
104 g_source_remove (chooser->populate_idle);
105
106 g_variant_unref (chooser->data);
107 g_object_unref (chooser->settings);
108
109 g_clear_object (&chooser->recent_long_press)do { _Static_assert (sizeof *((&chooser->recent_long_press
)) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&chooser->recent_long_press))) _pp = ((&chooser
->recent_long_press)); __typeof__ (*((&chooser->recent_long_press
))) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (g_object_unref
) (_ptr); } while (0)
;
110 g_clear_object (&chooser->recent_multi_press)do { _Static_assert (sizeof *((&chooser->recent_multi_press
)) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&chooser->recent_multi_press))) _pp = ((&chooser
->recent_multi_press)); __typeof__ (*((&chooser->recent_multi_press
))) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (g_object_unref
) (_ptr); } while (0)
;
111 g_clear_object (&chooser->people_long_press)do { _Static_assert (sizeof *((&chooser->people_long_press
)) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&chooser->people_long_press))) _pp = ((&chooser
->people_long_press)); __typeof__ (*((&chooser->people_long_press
))) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (g_object_unref
) (_ptr); } while (0)
;
112 g_clear_object (&chooser->people_multi_press)do { _Static_assert (sizeof *((&chooser->people_multi_press
)) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&chooser->people_multi_press))) _pp = ((&chooser
->people_multi_press)); __typeof__ (*((&chooser->people_multi_press
))) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (g_object_unref
) (_ptr); } while (0)
;
113 g_clear_object (&chooser->body_long_press)do { _Static_assert (sizeof *((&chooser->body_long_press
)) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&chooser->body_long_press))) _pp = ((&chooser->
body_long_press)); __typeof__ (*((&chooser->body_long_press
))) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (g_object_unref
) (_ptr); } while (0)
;
114 g_clear_object (&chooser->body_multi_press)do { _Static_assert (sizeof *((&chooser->body_multi_press
)) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&chooser->body_multi_press))) _pp = ((&chooser
->body_multi_press)); __typeof__ (*((&chooser->body_multi_press
))) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (g_object_unref
) (_ptr); } while (0)
;
115
116 G_OBJECT_CLASS (ctk_emoji_chooser_parent_class)((((GObjectClass*) (void *) ((ctk_emoji_chooser_parent_class)
))))
->finalize (object);
117}
118
119static void
120scroll_to_section (CtkButton *button,
121 gpointer data)
122{
123 EmojiSection *section = data;
124 CtkEmojiChooser *chooser;
125 CtkAdjustment *adj;
126 CtkAllocation alloc = { 0, 0, 0, 0 };
127
128 chooser = CTK_EMOJI_CHOOSER (ctk_widget_get_ancestor (CTK_WIDGET (button), CTK_TYPE_EMOJI_CHOOSER))((((CtkEmojiChooser*) (void *) ((ctk_widget_get_ancestor ((((
(CtkWidget*) (void *) ((button))))), (ctk_emoji_chooser_get_type
())))))))
;
129
130 adj = ctk_scrolled_window_get_vadjustment (CTK_SCROLLED_WINDOW (chooser->scrolled_window)((((CtkScrolledWindow*) (void *) ((chooser->scrolled_window
)))))
);
131
132 if (section->heading)
133 ctk_widget_get_allocation (section->heading, &alloc);
134
135 ctk_adjustment_animate_to_value (adj, alloc.y - BOX_SPACE6);
136}
137
138static void
139add_emoji (CtkWidget *box,
140 gboolean prepend,
141 GVariant *item,
142 gunichar modifier,
143 CtkEmojiChooser *chooser);
144
145#define MAX_RECENT(7*3) (7*3)
146
147static void
148populate_recent_section (CtkEmojiChooser *chooser)
149{
150 GVariant *variant;
151 GVariant *item;
152 GVariantIter iter;
153 gboolean empty = FALSE(0);
154
155 variant = g_settings_get_value (chooser->settings, "recent-emoji");
156 g_variant_iter_init (&iter, variant);
157 while ((item = g_variant_iter_next_value (&iter)))
158 {
159 GVariant *emoji_data;
160 gunichar modifier;
161
162 emoji_data = g_variant_get_child_value (item, 0);
163 g_variant_get_child (item, 1, "u", &modifier);
164 add_emoji (chooser->recent.box, FALSE(0), emoji_data, modifier, chooser);
165 g_variant_unref (emoji_data);
166 g_variant_unref (item);
167 empty = FALSE(0);
168 }
169
170 if (!empty)
171 {
172 ctk_widget_show (chooser->recent.box);
173 ctk_widget_set_sensitive (chooser->recent.button, TRUE(!(0)));
174 }
175 g_variant_unref (variant);
176}
177
178static void
179add_recent_item (CtkEmojiChooser *chooser,
180 GVariant *item,
181 gunichar modifier)
182{
183 GList *children, *l;
184 int i;
185 GVariantBuilder builder;
186
187 g_variant_ref (item);
188
189 g_variant_builder_init (&builder, G_VARIANT_TYPE ("a((auss)u)")((const GVariantType *) ("a((auss)u)")));
Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption
190 g_variant_builder_add (&builder, "(@(auss)u)", item, modifier);
191
192 children = ctk_container_get_children (CTK_CONTAINER (chooser->recent.box)((((CtkContainer*) (void *) ((chooser->recent.box))))));
193 for (l = children, i = 1; l; l = l->next, i++)
194 {
195 GVariant *item2 = g_object_get_data (G_OBJECT (l->data)((((GObject*) (void *) ((l->data))))), "emoji-data");
196 gunichar modifier2 = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (l->data), "modifier"))((guint) (gulong) (g_object_get_data (((((GObject*) (void *) (
(l->data))))), "modifier")))
;
197
198 if (modifier == modifier2 && g_variant_equal (item, item2))
199 {
200 ctk_widget_destroy (CTK_WIDGET (l->data)((((CtkWidget*) (void *) ((l->data))))));
201 i--;
202 continue;
203 }
204 if (i >= MAX_RECENT(7*3))
205 {
206 ctk_widget_destroy (CTK_WIDGET (l->data)((((CtkWidget*) (void *) ((l->data))))));
207 continue;
208 }
209
210 g_variant_builder_add (&builder, "(@(auss)u)", item2, modifier2);
211 }
212 g_list_free (children);
213
214 add_emoji (chooser->recent.box, TRUE(!(0)), item, modifier, chooser);
215
216 /* Enable recent */
217 ctk_widget_show (chooser->recent.box);
218 ctk_widget_set_sensitive (chooser->recent.button, TRUE(!(0)));
219
220 g_settings_set_value (chooser->settings, "recent-emoji", g_variant_builder_end (&builder));
221
222 g_variant_unref (item);
223}
224
225static void
226emoji_activated (CtkFlowBox *box G_GNUC_UNUSED__attribute__ ((__unused__)),
227 CtkFlowBoxChild *child,
228 gpointer data)
229{
230 CtkEmojiChooser *chooser = data;
231 char *text;
232 CtkWidget *ebox;
233 CtkWidget *label;
234 GVariant *item;
235 gunichar modifier;
236
237 ctk_popover_popdown (CTK_POPOVER (chooser)((((CtkPopover*) (void *) ((chooser))))));
238
239 ebox = ctk_bin_get_child (CTK_BIN (child)((((CtkBin*) (void *) ((child))))));
240 label = ctk_bin_get_child (CTK_BIN (ebox)((((CtkBin*) (void *) ((ebox))))));
241 text = g_strdup (ctk_label_get_label (CTK_LABEL (label)))g_strdup_inline (ctk_label_get_label (((((CtkLabel*) (void *)
((label)))))))
;
242
243 item = (GVariant*) g_object_get_data (G_OBJECT (child)((((GObject*) (void *) ((child))))), "emoji-data");
244 modifier = (gunichar) GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (child), "modifier"))((guint) (gulong) (g_object_get_data (((((GObject*) (void *) (
(child))))), "modifier")))
;
245 add_recent_item (chooser, item, modifier);
246
247 g_signal_emit (data, signals[EMOJI_PICKED], 0, text);
248 g_free (text);
249}
250
251static gboolean
252has_variations (GVariant *emoji_data)
253{
254 GVariant *codes;
255 int i;
256 gboolean has_variations;
257
258 has_variations = FALSE(0);
259 codes = g_variant_get_child_value (emoji_data, 0);
260 for (i = 0; i < g_variant_n_children (codes); i++)
261 {
262 gunichar code;
263 g_variant_get_child (codes, i, "u", &code);
264 if (code == 0)
265 {
266 has_variations = TRUE(!(0));
267 break;
268 }
269 }
270 g_variant_unref (codes);
271
272 return has_variations;
273}
274
275static void
276show_variations (CtkEmojiChooser *chooser,
277 CtkWidget *child)
278{
279 CtkWidget *popover;
280 CtkWidget *view;
281 CtkWidget *box;
282 GVariant *emoji_data;
283 CtkWidget *parent_popover;
284 gunichar modifier;
285
286 if (!child)
287 return;
288
289 emoji_data = (GVariant*) g_object_get_data (G_OBJECT (child)((((GObject*) (void *) ((child))))), "emoji-data");
290 if (!emoji_data)
291 return;
292
293 if (!has_variations (emoji_data))
294 return;
295
296 parent_popover = ctk_widget_get_ancestor (child, CTK_TYPE_POPOVER(ctk_popover_get_type ()));
297 popover = ctk_popover_new (child);
298 view = ctk_box_new (CTK_ORIENTATION_HORIZONTAL, 0);
299 ctk_style_context_add_class (ctk_widget_get_style_context (view), "view");
300 box = ctk_flow_box_new ();
301 ctk_flow_box_set_homogeneous (CTK_FLOW_BOX (box)((((CtkFlowBox*) (void *) ((box))))), TRUE(!(0)));
302 ctk_flow_box_set_min_children_per_line (CTK_FLOW_BOX (box)((((CtkFlowBox*) (void *) ((box))))), 6);
303 ctk_flow_box_set_max_children_per_line (CTK_FLOW_BOX (box)((((CtkFlowBox*) (void *) ((box))))), 6);
304 ctk_flow_box_set_activate_on_single_click (CTK_FLOW_BOX (box)((((CtkFlowBox*) (void *) ((box))))), TRUE(!(0)));
305 ctk_flow_box_set_selection_mode (CTK_FLOW_BOX (box)((((CtkFlowBox*) (void *) ((box))))), CTK_SELECTION_NONE);
306 ctk_container_add (CTK_CONTAINER (popover)((((CtkContainer*) (void *) ((popover))))), view);
307 ctk_container_add (CTK_CONTAINER (view)((((CtkContainer*) (void *) ((view))))), box);
308
309 g_signal_connect (box, "child-activated", G_CALLBACK (emoji_activated), parent_popover)g_signal_connect_data ((box), ("child-activated"), (((GCallback
) (emoji_activated))), (parent_popover), ((void*)0), (GConnectFlags
) 0)
;
310
311 add_emoji (box, FALSE(0), emoji_data, 0, chooser);
312 for (modifier = 0x1f3fb; modifier <= 0x1f3ff; modifier++)
313 add_emoji (box, FALSE(0), emoji_data, modifier, chooser);
314
315 ctk_widget_show_all (view);
316 ctk_popover_popup (CTK_POPOVER (popover)((((CtkPopover*) (void *) ((popover))))));
317}
318
319static void
320update_hover (CtkWidget *widget,
321 CdkEvent *event,
322 gpointer data G_GNUC_UNUSED__attribute__ ((__unused__)))
323{
324 if (event->type == CDK_ENTER_NOTIFY)
325 ctk_widget_set_state_flags (widget, CTK_STATE_FLAG_PRELIGHT, FALSE(0));
326 else
327 ctk_widget_unset_state_flags (widget, CTK_STATE_FLAG_PRELIGHT);
328}
329
330static void
331long_pressed_cb (CtkGesture *gesture,
332 double x,
333 double y,
334 gpointer data)
335{
336 CtkEmojiChooser *chooser = data;
337 CtkWidget *box;
338 CtkWidget *child;
339
340 box = ctk_event_controller_get_widget (CTK_EVENT_CONTROLLER (gesture)((((CtkEventController*) (void *) ((gesture))))));
341 child = CTK_WIDGET (ctk_flow_box_get_child_at_pos (CTK_FLOW_BOX (box), x, y))((((CtkWidget*) (void *) ((ctk_flow_box_get_child_at_pos ((((
(CtkFlowBox*) (void *) ((box))))), x, y))))))
;
342 show_variations (chooser, child);
343}
344
345static void
346pressed_cb (CtkGesture *gesture,
347 int n_press G_GNUC_UNUSED__attribute__ ((__unused__)),
348 double x,
349 double y,
350 gpointer data)
351{
352 CtkEmojiChooser *chooser = data;
353 CtkWidget *box;
354 CtkWidget *child;
355
356 box = ctk_event_controller_get_widget (CTK_EVENT_CONTROLLER (gesture)((((CtkEventController*) (void *) ((gesture))))));
357 child = CTK_WIDGET (ctk_flow_box_get_child_at_pos (CTK_FLOW_BOX (box), x, y))((((CtkWidget*) (void *) ((ctk_flow_box_get_child_at_pos ((((
(CtkFlowBox*) (void *) ((box))))), x, y))))))
;
358 show_variations (chooser, child);
359}
360
361static gboolean
362popup_menu (CtkWidget *widget,
363 gpointer data)
364{
365 CtkEmojiChooser *chooser = data;
366
367 show_variations (chooser, widget);
368 return TRUE(!(0));
369}
370
371static void
372add_emoji (CtkWidget *box,
373 gboolean prepend,
374 GVariant *item,
375 gunichar modifier,
376 CtkEmojiChooser *chooser)
377{
378 CtkWidget *child;
379 CtkWidget *ebox;
380 CtkWidget *label;
381 PangoAttrList *attrs;
382 GVariant *codes;
383 char text[64];
384 char *p = text;
385 int i;
386 PangoLayout *layout;
387 PangoRectangle rect;
388
389 codes = g_variant_get_child_value (item, 0);
390 for (i = 0; i < g_variant_n_children (codes); i++)
391 {
392 gunichar code;
393
394 g_variant_get_child (codes, i, "u", &code);
395 if (code == 0)
396 code = modifier;
397 if (code != 0)
398 p += g_unichar_to_utf8 (code, p);
399 }
400 g_variant_unref (codes);
401 p += g_unichar_to_utf8 (0xFE0F, p); /* U+FE0F is the Emoji variation selector */
402 p[0] = 0;
403
404 label = ctk_label_new (text);
405 attrs = pango_attr_list_new ();
406 pango_attr_list_insert (attrs, pango_attr_scale_new (PANGO_SCALE_X_LARGE((double)1.44)));
407 ctk_label_set_attributes (CTK_LABEL (label)((((CtkLabel*) (void *) ((label))))), attrs);
408 pango_attr_list_unref (attrs);
409
410 layout = ctk_label_get_layout (CTK_LABEL (label)((((CtkLabel*) (void *) ((label))))));
411 pango_layout_get_extents (layout, &rect, NULL((void*)0));
412
413 /* Check for fallback rendering that generates too wide items */
414 if (pango_layout_get_unknown_glyphs_count (layout) > 0 ||
415 rect.width >= 1.5 * chooser->emoji_max_width)
416 {
417 ctk_widget_destroy (label);
418 return;
419 }
420
421 child = ctk_flow_box_child_new ();
422 ctk_style_context_add_class (ctk_widget_get_style_context (child), "emoji");
423 g_object_set_data_full (G_OBJECT (child)((((GObject*) (void *) ((child))))), "emoji-data",
424 g_variant_ref (item),
425 (GDestroyNotify)g_variant_unref);
426 if (modifier != 0)
427 g_object_set_data (G_OBJECT (child)((((GObject*) (void *) ((child))))), "modifier", GUINT_TO_POINTER (modifier)((gpointer) (gulong) (modifier)));
428
429 ebox = ctk_event_box_new ();
430 ctk_widget_add_events (ebox, CDK_ENTER_NOTIFY_MASK | CDK_LEAVE_NOTIFY_MASK);
431 g_signal_connect (ebox, "enter-notify-event", G_CALLBACK (update_hover), FALSE)g_signal_connect_data ((ebox), ("enter-notify-event"), (((GCallback
) (update_hover))), ((0)), ((void*)0), (GConnectFlags) 0)
;
432 g_signal_connect (ebox, "leave-notify-event", G_CALLBACK (update_hover), FALSE)g_signal_connect_data ((ebox), ("leave-notify-event"), (((GCallback
) (update_hover))), ((0)), ((void*)0), (GConnectFlags) 0)
;
433 ctk_container_add (CTK_CONTAINER (child)((((CtkContainer*) (void *) ((child))))), ebox);
434 ctk_container_add (CTK_CONTAINER (ebox)((((CtkContainer*) (void *) ((ebox))))), label);
435 ctk_widget_show_all (child);
436
437 if (chooser)
438 g_signal_connect (child, "popup-menu", G_CALLBACK (popup_menu), chooser)g_signal_connect_data ((child), ("popup-menu"), (((GCallback)
(popup_menu))), (chooser), ((void*)0), (GConnectFlags) 0)
;
439
440 ctk_flow_box_insert (CTK_FLOW_BOX (box)((((CtkFlowBox*) (void *) ((box))))), child, prepend ? 0 : -1);
441}
442
443static gboolean
444populate_emoji_chooser (gpointer data)
445{
446 CtkEmojiChooser *chooser = data;
447 GBytes *bytes = NULL((void*)0);
448 GVariant *item;
449 guint64 start, now;
450
451 start = g_get_monotonic_time ();
452
453 if (!chooser->data)
454 {
455 bytes = g_resources_lookup_data ("/org/ctk/libctk/emoji/emoji.data", 0, NULL((void*)0));
456 chooser->data = g_variant_ref_sink (g_variant_new_from_bytes (G_VARIANT_TYPE ("a(auss)")((const GVariantType *) ("a(auss)")), bytes, TRUE(!(0))));
457 }
458
459 if (!chooser->iter)
460 {
461 chooser->iter = g_variant_iter_new (chooser->data);
462 chooser->box = chooser->people.box;
463 }
464 while ((item = g_variant_iter_next_value (chooser->iter)))
465 {
466 const char *name;
467
468 g_variant_get_child (item, 1, "&s", &name);
469
470 if (strcmp (name, chooser->body.first) == 0)
471 chooser->box = chooser->body.box;
472 else if (strcmp (name, chooser->nature.first) == 0)
473 chooser->box = chooser->nature.box;
474 else if (strcmp (name, chooser->food.first) == 0)
475 chooser->box = chooser->food.box;
476 else if (strcmp (name, chooser->travel.first) == 0)
477 chooser->box = chooser->travel.box;
478 else if (strcmp (name, chooser->activities.first) == 0)
479 chooser->box = chooser->activities.box;
480 else if (strcmp (name, chooser->objects.first) == 0)
481 chooser->box = chooser->objects.box;
482 else if (strcmp (name, chooser->symbols.first) == 0)
483 chooser->box = chooser->symbols.box;
484 else if (strcmp (name, chooser->flags.first) == 0)
485 chooser->box = chooser->flags.box;
486
487 add_emoji (chooser->box, FALSE(0), item, 0, chooser);
488 g_variant_unref (item);
489
490 now = g_get_monotonic_time ();
491 if (now > start + 8000)
492 return G_SOURCE_CONTINUE(!(0));
493 }
494
495 /* We scroll to the top on show, so check the right button for the 1st time */
496 ctk_widget_set_state_flags (chooser->recent.button, CTK_STATE_FLAG_CHECKED, FALSE(0));
497
498 g_variant_iter_free (chooser->iter);
499 chooser->iter = NULL((void*)0);
500 chooser->box = NULL((void*)0);
501 chooser->populate_idle = 0;
502
503 return G_SOURCE_REMOVE(0);
504}
505
506static void
507adj_value_changed (CtkAdjustment *adj,
508 gpointer data)
509{
510 CtkEmojiChooser *chooser = data;
511 double value = ctk_adjustment_get_value (adj);
512 EmojiSection const *sections[] = {
513 &chooser->recent,
514 &chooser->people,
515 &chooser->body,
516 &chooser->nature,
517 &chooser->food,
518 &chooser->travel,
519 &chooser->activities,
520 &chooser->objects,
521 &chooser->symbols,
522 &chooser->flags,
523 };
524 EmojiSection const *select_section = sections[0];
525 gsize i;
526
527 /* Figure out which section the current scroll position is within */
528 for (i = 0; i < G_N_ELEMENTS (sections)(sizeof (sections) / sizeof ((sections)[0])); ++i)
529 {
530 EmojiSection const *section = sections[i];
531 CtkAllocation alloc;
532
533 if (section->heading)
534 ctk_widget_get_allocation (section->heading, &alloc);
535 else
536 ctk_widget_get_allocation (section->box, &alloc);
537
538 if (value < alloc.y - BOX_SPACE6)
539 break;
540
541 select_section = section;
542 }
543
544 /* Un/Check the section buttons accordingly */
545 for (i = 0; i < G_N_ELEMENTS (sections)(sizeof (sections) / sizeof ((sections)[0])); ++i)
546 {
547 EmojiSection const *section = sections[i];
548
549 if (section == select_section)
550 ctk_widget_set_state_flags (section->button, CTK_STATE_FLAG_CHECKED, FALSE(0));
551 else
552 ctk_widget_unset_state_flags (section->button, CTK_STATE_FLAG_CHECKED);
553 }
554}
555
556static gboolean
557filter_func (CtkFlowBoxChild *child,
558 gpointer data)
559{
560 EmojiSection *section = data;
561 CtkEmojiChooser *chooser;
562 GVariant *emoji_data;
563 const char *text;
564 const char *name;
565 gboolean res;
566
567 res = TRUE(!(0));
568
569 chooser = CTK_EMOJI_CHOOSER (ctk_widget_get_ancestor (CTK_WIDGET (child), CTK_TYPE_EMOJI_CHOOSER))((((CtkEmojiChooser*) (void *) ((ctk_widget_get_ancestor ((((
(CtkWidget*) (void *) ((child))))), (ctk_emoji_chooser_get_type
())))))))
;
570 text = ctk_entry_get_text (CTK_ENTRY (chooser->search_entry)((((CtkEntry*) (void *) ((chooser->search_entry))))));
571 emoji_data = (GVariant *) g_object_get_data (G_OBJECT (child)((((GObject*) (void *) ((child))))), "emoji-data");
572
573 if (text[0] == 0)
574 goto out;
575
576 if (!emoji_data)
577 goto out;
578
579 g_variant_get_child (emoji_data, 1, "&s", &name);
580 res = g_str_match_string (text, name, TRUE(!(0)));
581
582out:
583 if (res)
584 section->empty = FALSE(0);
585
586 return res;
587}
588
589static void
590invalidate_section (EmojiSection *section)
591{
592 section->empty = TRUE(!(0));
593 ctk_flow_box_invalidate_filter (CTK_FLOW_BOX (section->box)((((CtkFlowBox*) (void *) ((section->box))))));
594}
595
596static void
597update_headings (CtkEmojiChooser *chooser)
598{
599 ctk_widget_set_visible (chooser->people.heading, !chooser->people.empty);
600 ctk_widget_set_visible (chooser->people.box, !chooser->people.empty);
601 ctk_widget_set_visible (chooser->body.heading, !chooser->body.empty);
602 ctk_widget_set_visible (chooser->body.box, !chooser->body.empty);
603 ctk_widget_set_visible (chooser->nature.heading, !chooser->nature.empty);
604 ctk_widget_set_visible (chooser->nature.box, !chooser->nature.empty);
605 ctk_widget_set_visible (chooser->food.heading, !chooser->food.empty);
606 ctk_widget_set_visible (chooser->food.box, !chooser->food.empty);
607 ctk_widget_set_visible (chooser->travel.heading, !chooser->travel.empty);
608 ctk_widget_set_visible (chooser->travel.box, !chooser->travel.empty);
609 ctk_widget_set_visible (chooser->activities.heading, !chooser->activities.empty);
610 ctk_widget_set_visible (chooser->activities.box, !chooser->activities.empty);
611 ctk_widget_set_visible (chooser->objects.heading, !chooser->objects.empty);
612 ctk_widget_set_visible (chooser->objects.box, !chooser->objects.empty);
613 ctk_widget_set_visible (chooser->symbols.heading, !chooser->symbols.empty);
614 ctk_widget_set_visible (chooser->symbols.box, !chooser->symbols.empty);
615 ctk_widget_set_visible (chooser->flags.heading, !chooser->flags.empty);
616 ctk_widget_set_visible (chooser->flags.box, !chooser->flags.empty);
617
618 if (chooser->recent.empty && chooser->people.empty &&
619 chooser->body.empty && chooser->nature.empty &&
620 chooser->food.empty && chooser->travel.empty &&
621 chooser->activities.empty && chooser->objects.empty &&
622 chooser->symbols.empty && chooser->flags.empty)
623 ctk_stack_set_visible_child_name (CTK_STACK (chooser->stack)((((CtkStack*) (void *) ((chooser->stack))))), "empty");
624 else
625 ctk_stack_set_visible_child_name (CTK_STACK (chooser->stack)((((CtkStack*) (void *) ((chooser->stack))))), "list");
626}
627
628static void
629search_changed (CtkEntry *entry G_GNUC_UNUSED__attribute__ ((__unused__)),
630 gpointer data)
631{
632 CtkEmojiChooser *chooser = data;
633
634 invalidate_section (&chooser->recent);
635 invalidate_section (&chooser->people);
636 invalidate_section (&chooser->body);
637 invalidate_section (&chooser->nature);
638 invalidate_section (&chooser->food);
639 invalidate_section (&chooser->travel);
640 invalidate_section (&chooser->activities);
641 invalidate_section (&chooser->objects);
642 invalidate_section (&chooser->symbols);
643 invalidate_section (&chooser->flags);
644
645 update_headings (chooser);
646}
647
648static void
649setup_section (CtkEmojiChooser *chooser,
650 EmojiSection *section,
651 const char *first,
652 const char *icon)
653{
654 CtkAdjustment *adj;
655 CtkWidget *image;
656
657 section->first = first;
658
659 image = ctk_bin_get_child (CTK_BIN (section->button)((((CtkBin*) (void *) ((section->button))))));
660 ctk_image_set_from_icon_name (CTK_IMAGE (image)((((CtkImage*) (void *) ((image))))), icon, CTK_ICON_SIZE_BUTTON);
661
662 adj = ctk_scrolled_window_get_vadjustment (CTK_SCROLLED_WINDOW (chooser->scrolled_window)((((CtkScrolledWindow*) (void *) ((chooser->scrolled_window
)))))
);
663
664 ctk_container_set_focus_vadjustment (CTK_CONTAINER (section->box)((((CtkContainer*) (void *) ((section->box))))), adj);
665 ctk_flow_box_set_filter_func (CTK_FLOW_BOX (section->box)((((CtkFlowBox*) (void *) ((section->box))))), filter_func, section, NULL((void*)0));
666 g_signal_connect (section->button, "clicked", G_CALLBACK (scroll_to_section), section)g_signal_connect_data ((section->button), ("clicked"), (((
GCallback) (scroll_to_section))), (section), ((void*)0), (GConnectFlags
) 0)
;
667}
668
669static void
670ctk_emoji_chooser_init (CtkEmojiChooser *chooser)
671{
672 CtkAdjustment *adj;
673
674 chooser->settings = g_settings_new ("org.ctk.Settings.EmojiChooser");
675
676 ctk_widget_init_template (CTK_WIDGET (chooser)((((CtkWidget*) (void *) ((chooser))))));
677
678 /* Get a reasonable maximum width for an emoji. We do this to
679 * skip overly wide fallback rendering for certain emojis the
680 * font does not contain and therefore end up being rendered
681 * as multiply glyphs.
682 */
683 {
684 PangoLayout *layout = ctk_widget_create_pango_layout (CTK_WIDGET (chooser)((((CtkWidget*) (void *) ((chooser))))), "🙂");
685 PangoAttrList *attrs;
686 PangoRectangle rect;
687
688 attrs = pango_attr_list_new ();
689 pango_attr_list_insert (attrs, pango_attr_scale_new (PANGO_SCALE_X_LARGE((double)1.44)));
690 pango_layout_set_attributes (layout, attrs);
691 pango_attr_list_unref (attrs);
692
693 pango_layout_get_extents (layout, &rect, NULL((void*)0));
694 chooser->emoji_max_width = rect.width;
695
696 g_object_unref (layout);
697 }
698
699 chooser->recent_long_press = ctk_gesture_long_press_new (chooser->recent.box);
700 g_signal_connect (chooser->recent_long_press, "pressed", G_CALLBACK (long_pressed_cb), chooser)g_signal_connect_data ((chooser->recent_long_press), ("pressed"
), (((GCallback) (long_pressed_cb))), (chooser), ((void*)0), (
GConnectFlags) 0)
;
701 chooser->recent_multi_press = ctk_gesture_multi_press_new (chooser->recent.box);
702 ctk_gesture_single_set_button (CTK_GESTURE_SINGLE (chooser->recent_multi_press)((((CtkGestureSingle*) (void *) ((chooser->recent_multi_press
)))))
, CDK_BUTTON_SECONDARY(3));
703 g_signal_connect (chooser->recent_multi_press, "pressed", G_CALLBACK (pressed_cb), chooser)g_signal_connect_data ((chooser->recent_multi_press), ("pressed"
), (((GCallback) (pressed_cb))), (chooser), ((void*)0), (GConnectFlags
) 0)
;
704
705 chooser->people_long_press = ctk_gesture_long_press_new (chooser->people.box);
706 g_signal_connect (chooser->people_long_press, "pressed", G_CALLBACK (long_pressed_cb), chooser)g_signal_connect_data ((chooser->people_long_press), ("pressed"
), (((GCallback) (long_pressed_cb))), (chooser), ((void*)0), (
GConnectFlags) 0)
;
707 chooser->people_multi_press = ctk_gesture_multi_press_new (chooser->people.box);
708 ctk_gesture_single_set_button (CTK_GESTURE_SINGLE (chooser->people_multi_press)((((CtkGestureSingle*) (void *) ((chooser->people_multi_press
)))))
, CDK_BUTTON_SECONDARY(3));
709 g_signal_connect (chooser->people_multi_press, "pressed", G_CALLBACK (pressed_cb), chooser)g_signal_connect_data ((chooser->people_multi_press), ("pressed"
), (((GCallback) (pressed_cb))), (chooser), ((void*)0), (GConnectFlags
) 0)
;
710
711 chooser->body_long_press = ctk_gesture_long_press_new (chooser->body.box);
712 g_signal_connect (chooser->body_long_press, "pressed", G_CALLBACK (long_pressed_cb), chooser)g_signal_connect_data ((chooser->body_long_press), ("pressed"
), (((GCallback) (long_pressed_cb))), (chooser), ((void*)0), (
GConnectFlags) 0)
;
713 chooser->body_multi_press = ctk_gesture_multi_press_new (chooser->body.box);
714 ctk_gesture_single_set_button (CTK_GESTURE_SINGLE (chooser->body_multi_press)((((CtkGestureSingle*) (void *) ((chooser->body_multi_press
)))))
, CDK_BUTTON_SECONDARY(3));
715 g_signal_connect (chooser->body_multi_press, "pressed", G_CALLBACK (pressed_cb), chooser)g_signal_connect_data ((chooser->body_multi_press), ("pressed"
), (((GCallback) (pressed_cb))), (chooser), ((void*)0), (GConnectFlags
) 0)
;
716
717 adj = ctk_scrolled_window_get_vadjustment (CTK_SCROLLED_WINDOW (chooser->scrolled_window)((((CtkScrolledWindow*) (void *) ((chooser->scrolled_window
)))))
);
718 g_signal_connect (adj, "value-changed", G_CALLBACK (adj_value_changed), chooser)g_signal_connect_data ((adj), ("value-changed"), (((GCallback
) (adj_value_changed))), (chooser), ((void*)0), (GConnectFlags
) 0)
;
719
720 setup_section (chooser, &chooser->recent, NULL((void*)0), "emoji-recent-symbolic");
721 setup_section (chooser, &chooser->people, "grinning face", "emoji-people-symbolic");
722 setup_section (chooser, &chooser->body, "selfie", "emoji-body-symbolic");
723 setup_section (chooser, &chooser->nature, "monkey face", "emoji-nature-symbolic");
724 setup_section (chooser, &chooser->food, "grapes", "emoji-food-symbolic");
725 setup_section (chooser, &chooser->travel, "globe showing Europe-Africa", "emoji-travel-symbolic");
726 setup_section (chooser, &chooser->activities, "jack-o-lantern", "emoji-activities-symbolic");
727 setup_section (chooser, &chooser->objects, "muted speaker", "emoji-objects-symbolic");
728 setup_section (chooser, &chooser->symbols, "ATM sign", "emoji-symbols-symbolic");
729 setup_section (chooser, &chooser->flags, "chequered flag", "emoji-flags-symbolic");
730
731 populate_recent_section (chooser);
732
733 chooser->populate_idle = g_idle_add (populate_emoji_chooser, chooser);
734 g_source_set_name_by_id (chooser->populate_idle, "[ctk] populate_emoji_chooser");
735}
736
737static void
738ctk_emoji_chooser_show (CtkWidget *widget)
739{
740 CtkEmojiChooser *chooser = CTK_EMOJI_CHOOSER (widget)((((CtkEmojiChooser*) (void *) ((widget)))));
741 CtkAdjustment *adj;
742
743 CTK_WIDGET_CLASS (ctk_emoji_chooser_parent_class)((((CtkWidgetClass*) (void *) ((ctk_emoji_chooser_parent_class
)))))
->show (widget);
744
745 adj = ctk_scrolled_window_get_vadjustment (CTK_SCROLLED_WINDOW (chooser->scrolled_window)((((CtkScrolledWindow*) (void *) ((chooser->scrolled_window
)))))
);
746 ctk_adjustment_set_value (adj, 0);
747
748 ctk_entry_set_text (CTK_ENTRY (chooser->search_entry)((((CtkEntry*) (void *) ((chooser->search_entry))))), "");
749}
750
751static void
752ctk_emoji_chooser_class_init (CtkEmojiChooserClass *klass)
753{
754 GObjectClass *object_class = G_OBJECT_CLASS (klass)((((GObjectClass*) (void *) ((klass)))));
755 CtkWidgetClass *widget_class = CTK_WIDGET_CLASS (klass)((((CtkWidgetClass*) (void *) ((klass)))));
756
757 object_class->finalize = ctk_emoji_chooser_finalize;
758 widget_class->show = ctk_emoji_chooser_show;
759
760 signals[EMOJI_PICKED] = g_signal_new ("emoji-picked",
761 G_OBJECT_CLASS_TYPE (object_class)((((GTypeClass*) (object_class))->g_type)),
762 G_SIGNAL_RUN_LAST,
763 0,
764 NULL((void*)0), NULL((void*)0),
765 NULL((void*)0),
766 G_TYPE_NONE((GType) ((1) << (2))), 1, G_TYPE_STRING((GType) ((16) << (2)))|G_SIGNAL_TYPE_STATIC_SCOPE(((GType) (1 << 0))));
767
768 ctk_widget_class_set_template_from_resource (widget_class, "/org/ctk/libctk/ui/ctkemojichooser.ui");
769
770 ctk_widget_class_bind_template_child (widget_class, CtkEmojiChooser, search_entry)ctk_widget_class_bind_template_child_full (widget_class, "search_entry"
, (0), ((glong) __builtin_offsetof(CtkEmojiChooser, search_entry
)))
;
771 ctk_widget_class_bind_template_child (widget_class, CtkEmojiChooser, stack)ctk_widget_class_bind_template_child_full (widget_class, "stack"
, (0), ((glong) __builtin_offsetof(CtkEmojiChooser, stack)))
;
772 ctk_widget_class_bind_template_child (widget_class, CtkEmojiChooser, scrolled_window)ctk_widget_class_bind_template_child_full (widget_class, "scrolled_window"
, (0), ((glong) __builtin_offsetof(CtkEmojiChooser, scrolled_window
)))
;
773
774 ctk_widget_class_bind_template_child (widget_class, CtkEmojiChooser, recent.box)ctk_widget_class_bind_template_child_full (widget_class, "recent.box"
, (0), ((glong) __builtin_offsetof(CtkEmojiChooser, recent.box
)))
;
775 ctk_widget_class_bind_template_child (widget_class, CtkEmojiChooser, recent.button)ctk_widget_class_bind_template_child_full (widget_class, "recent.button"
, (0), ((glong) __builtin_offsetof(CtkEmojiChooser, recent.button
)))
;
776
777 ctk_widget_class_bind_template_child (widget_class, CtkEmojiChooser, people.box)ctk_widget_class_bind_template_child_full (widget_class, "people.box"
, (0), ((glong) __builtin_offsetof(CtkEmojiChooser, people.box
)))
;
778 ctk_widget_class_bind_template_child (widget_class, CtkEmojiChooser, people.heading)ctk_widget_class_bind_template_child_full (widget_class, "people.heading"
, (0), ((glong) __builtin_offsetof(CtkEmojiChooser, people.heading
)))
;
779 ctk_widget_class_bind_template_child (widget_class, CtkEmojiChooser, people.button)ctk_widget_class_bind_template_child_full (widget_class, "people.button"
, (0), ((glong) __builtin_offsetof(CtkEmojiChooser, people.button
)))
;
780
781 ctk_widget_class_bind_template_child (widget_class, CtkEmojiChooser, body.box)ctk_widget_class_bind_template_child_full (widget_class, "body.box"
, (0), ((glong) __builtin_offsetof(CtkEmojiChooser, body.box)
))
;
782 ctk_widget_class_bind_template_child (widget_class, CtkEmojiChooser, body.heading)ctk_widget_class_bind_template_child_full (widget_class, "body.heading"
, (0), ((glong) __builtin_offsetof(CtkEmojiChooser, body.heading
)))
;
783 ctk_widget_class_bind_template_child (widget_class, CtkEmojiChooser, body.button)ctk_widget_class_bind_template_child_full (widget_class, "body.button"
, (0), ((glong) __builtin_offsetof(CtkEmojiChooser, body.button
)))
;
784
785 ctk_widget_class_bind_template_child (widget_class, CtkEmojiChooser, nature.box)ctk_widget_class_bind_template_child_full (widget_class, "nature.box"
, (0), ((glong) __builtin_offsetof(CtkEmojiChooser, nature.box
)))
;
786 ctk_widget_class_bind_template_child (widget_class, CtkEmojiChooser, nature.heading)ctk_widget_class_bind_template_child_full (widget_class, "nature.heading"
, (0), ((glong) __builtin_offsetof(CtkEmojiChooser, nature.heading
)))
;
787 ctk_widget_class_bind_template_child (widget_class, CtkEmojiChooser, nature.button)ctk_widget_class_bind_template_child_full (widget_class, "nature.button"
, (0), ((glong) __builtin_offsetof(CtkEmojiChooser, nature.button
)))
;
788
789 ctk_widget_class_bind_template_child (widget_class, CtkEmojiChooser, food.box)ctk_widget_class_bind_template_child_full (widget_class, "food.box"
, (0), ((glong) __builtin_offsetof(CtkEmojiChooser, food.box)
))
;
790 ctk_widget_class_bind_template_child (widget_class, CtkEmojiChooser, food.heading)ctk_widget_class_bind_template_child_full (widget_class, "food.heading"
, (0), ((glong) __builtin_offsetof(CtkEmojiChooser, food.heading
)))
;
791 ctk_widget_class_bind_template_child (widget_class, CtkEmojiChooser, food.button)ctk_widget_class_bind_template_child_full (widget_class, "food.button"
, (0), ((glong) __builtin_offsetof(CtkEmojiChooser, food.button
)))
;
792
793 ctk_widget_class_bind_template_child (widget_class, CtkEmojiChooser, travel.box)ctk_widget_class_bind_template_child_full (widget_class, "travel.box"
, (0), ((glong) __builtin_offsetof(CtkEmojiChooser, travel.box
)))
;
794 ctk_widget_class_bind_template_child (widget_class, CtkEmojiChooser, travel.heading)ctk_widget_class_bind_template_child_full (widget_class, "travel.heading"
, (0), ((glong) __builtin_offsetof(CtkEmojiChooser, travel.heading
)))
;
795 ctk_widget_class_bind_template_child (widget_class, CtkEmojiChooser, travel.button)ctk_widget_class_bind_template_child_full (widget_class, "travel.button"
, (0), ((glong) __builtin_offsetof(CtkEmojiChooser, travel.button
)))
;
796
797 ctk_widget_class_bind_template_child (widget_class, CtkEmojiChooser, activities.box)ctk_widget_class_bind_template_child_full (widget_class, "activities.box"
, (0), ((glong) __builtin_offsetof(CtkEmojiChooser, activities
.box)))
;
798 ctk_widget_class_bind_template_child (widget_class, CtkEmojiChooser, activities.heading)ctk_widget_class_bind_template_child_full (widget_class, "activities.heading"
, (0), ((glong) __builtin_offsetof(CtkEmojiChooser, activities
.heading)))
;
799 ctk_widget_class_bind_template_child (widget_class, CtkEmojiChooser, activities.button)ctk_widget_class_bind_template_child_full (widget_class, "activities.button"
, (0), ((glong) __builtin_offsetof(CtkEmojiChooser, activities
.button)))
;
800
801 ctk_widget_class_bind_template_child (widget_class, CtkEmojiChooser, objects.box)ctk_widget_class_bind_template_child_full (widget_class, "objects.box"
, (0), ((glong) __builtin_offsetof(CtkEmojiChooser, objects.box
)))
;
802 ctk_widget_class_bind_template_child (widget_class, CtkEmojiChooser, objects.heading)ctk_widget_class_bind_template_child_full (widget_class, "objects.heading"
, (0), ((glong) __builtin_offsetof(CtkEmojiChooser, objects.heading
)))
;
803 ctk_widget_class_bind_template_child (widget_class, CtkEmojiChooser, objects.button)ctk_widget_class_bind_template_child_full (widget_class, "objects.button"
, (0), ((glong) __builtin_offsetof(CtkEmojiChooser, objects.button
)))
;
804
805 ctk_widget_class_bind_template_child (widget_class, CtkEmojiChooser, symbols.box)ctk_widget_class_bind_template_child_full (widget_class, "symbols.box"
, (0), ((glong) __builtin_offsetof(CtkEmojiChooser, symbols.box
)))
;
806 ctk_widget_class_bind_template_child (widget_class, CtkEmojiChooser, symbols.heading)ctk_widget_class_bind_template_child_full (widget_class, "symbols.heading"
, (0), ((glong) __builtin_offsetof(CtkEmojiChooser, symbols.heading
)))
;
807 ctk_widget_class_bind_template_child (widget_class, CtkEmojiChooser, symbols.button)ctk_widget_class_bind_template_child_full (widget_class, "symbols.button"
, (0), ((glong) __builtin_offsetof(CtkEmojiChooser, symbols.button
)))
;
808
809 ctk_widget_class_bind_template_child (widget_class, CtkEmojiChooser, flags.box)ctk_widget_class_bind_template_child_full (widget_class, "flags.box"
, (0), ((glong) __builtin_offsetof(CtkEmojiChooser, flags.box
)))
;
810 ctk_widget_class_bind_template_child (widget_class, CtkEmojiChooser, flags.heading)ctk_widget_class_bind_template_child_full (widget_class, "flags.heading"
, (0), ((glong) __builtin_offsetof(CtkEmojiChooser, flags.heading
)))
;
811 ctk_widget_class_bind_template_child (widget_class, CtkEmojiChooser, flags.button)ctk_widget_class_bind_template_child_full (widget_class, "flags.button"
, (0), ((glong) __builtin_offsetof(CtkEmojiChooser, flags.button
)))
;
812
813 ctk_widget_class_bind_template_callback (widget_class, emoji_activated)ctk_widget_class_bind_template_callback_full (((((CtkWidgetClass
*) (void *) ((widget_class))))), "emoji_activated", ((GCallback
) (emoji_activated)))
;
814 ctk_widget_class_bind_template_callback (widget_class, search_changed)ctk_widget_class_bind_template_callback_full (((((CtkWidgetClass
*) (void *) ((widget_class))))), "search_changed", ((GCallback
) (search_changed)))
;
815}
816
817CtkWidget *
818ctk_emoji_chooser_new (void)
819{
820 return CTK_WIDGET (g_object_new (CTK_TYPE_EMOJI_CHOOSER, NULL))((((CtkWidget*) (void *) ((g_object_new ((ctk_emoji_chooser_get_type
()), ((void*)0)))))))
;
821}