1/* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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/*
19 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
20 * file for a list of people on the GTK+ Team. See the ChangeLog
21 * files for a list of changes. These files are distributed with
22 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
23 */
24
25#include "config.h"
26
27#include "gtkwidgetprivate.h"
28
29#include "gtkaccelgroupprivate.h"
30#include "gtkaccessibleprivate.h"
31#include "gtkactionobserverprivate.h"
32#include "gtkapplicationprivate.h"
33#include "gtkbuildable.h"
34#include "gtkbuilderprivate.h"
35#include "gtkconstraint.h"
36#include "gtkcssboxesprivate.h"
37#include "gtkcssfiltervalueprivate.h"
38#include "gtkcsstransformvalueprivate.h"
39#include "gtkcsspositionvalueprivate.h"
40#include "gtkcssfontvariationsvalueprivate.h"
41#include "gtkcssnumbervalueprivate.h"
42#include "gtkcsswidgetnodeprivate.h"
43#include "gtkdebug.h"
44#include "gtkgesturedrag.h"
45#include "gtkgestureprivate.h"
46#include "gtkgesturesingle.h"
47#include "gtkgestureswipe.h"
48#include "gtkgestureprivate.h"
49#include "gtkintl.h"
50#include "gtklayoutmanagerprivate.h"
51#include "gtkmain.h"
52#include "gtkmarshalers.h"
53#include "gtknative.h"
54#include "gtkpopover.h"
55#include "gtkprivate.h"
56#include "gtkrenderbackgroundprivate.h"
57#include "gtkrenderborderprivate.h"
58#include "gtkrootprivate.h"
59#include "gtknativeprivate.h"
60#include "gtkscrollable.h"
61#include "gtksettingsprivate.h"
62#include "gtkshortcut.h"
63#include "gtkshortcutcontrollerprivate.h"
64#include "gtkshortcutmanager.h"
65#include "gtkshortcutmanagerprivate.h"
66#include "gtkshortcuttrigger.h"
67#include "gtksizegroup-private.h"
68#include "gtksnapshotprivate.h"
69#include "gtkstylecontextprivate.h"
70#include "gtktooltipprivate.h"
71#include "gsktransformprivate.h"
72#include "gtktypebuiltins.h"
73#include "gtkversion.h"
74#include "gtkwidgetpaintableprivate.h"
75#include "gtkwindowgroup.h"
76#include "gtkwindowprivate.h"
77#include "gtktestatcontextprivate.h"
78
79#include "inspector/window.h"
80
81#include "gdk/gdkeventsprivate.h"
82#include "gdk/gdkprofilerprivate.h"
83#include "gsk/gskdebugprivate.h"
84#include "gsk/gskrendererprivate.h"
85
86#include <cairo-gobject.h>
87#include <locale.h>
88#include <math.h>
89#include <stdarg.h>
90#include <string.h>
91
92/**
93 * GtkWidget:
94 *
95 * The base class for all widgets.
96 *
97 * `GtkWidget` is the base class all widgets in GTK derive from. It manages the
98 * widget lifecycle, layout, states and style.
99 *
100 * ### Height-for-width Geometry Management
101 *
102 * GTK uses a height-for-width (and width-for-height) geometry management
103 * system. Height-for-width means that a widget can change how much
104 * vertical space it needs, depending on the amount of horizontal space
105 * that it is given (and similar for width-for-height). The most common
106 * example is a label that reflows to fill up the available width, wraps
107 * to fewer lines, and therefore needs less height.
108 *
109 * Height-for-width geometry management is implemented in GTK by way
110 * of two virtual methods:
111 *
112 * - [vfunc@Gtk.Widget.get_request_mode]
113 * - [vfunc@Gtk.Widget.measure]
114 *
115 * There are some important things to keep in mind when implementing
116 * height-for-width and when using it in widget implementations.
117 *
118 * If you implement a direct `GtkWidget` subclass that supports
119 * height-for-width or width-for-height geometry management for itself
120 * or its child widgets, the [vfunc@Gtk.Widget.get_request_mode] virtual
121 * function must be implemented as well and return the widget's preferred
122 * request mode. The default implementation of this virtual function
123 * returns %GTK_SIZE_REQUEST_CONSTANT_SIZE, which means that the widget will
124 * only ever get -1 passed as the for_size value to its
125 * [vfunc@Gtk.Widget.measure] implementation.
126 *
127 * The geometry management system will query a widget hierarchy in
128 * only one orientation at a time. When widgets are initially queried
129 * for their minimum sizes it is generally done in two initial passes
130 * in the [enum@Gtk.SizeRequestMode] chosen by the toplevel.
131 *
132 * For example, when queried in the normal %GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH mode:
133 *
134 * First, the default minimum and natural width for each widget
135 * in the interface will be computed using [id@gtk_widget_measure] with an
136 * orientation of %GTK_ORIENTATION_HORIZONTAL and a for_size of -1.
137 * Because the preferred widths for each widget depend on the preferred
138 * widths of their children, this information propagates up the hierarchy,
139 * and finally a minimum and natural width is determined for the entire
140 * toplevel. Next, the toplevel will use the minimum width to query for the
141 * minimum height contextual to that width using [id@gtk_widget_measure] with an
142 * orientation of %GTK_ORIENTATION_VERTICAL and a for_size of the just computed
143 * width. This will also be a highly recursive operation. The minimum height
144 * for the minimum width is normally used to set the minimum size constraint
145 * on the toplevel.
146 *
147 * After the toplevel window has initially requested its size in both
148 * dimensions it can go on to allocate itself a reasonable size (or a size
149 * previously specified with [method@Gtk.Window.set_default_size]). During the
150 * recursive allocation process it’s important to note that request cycles
151 * will be recursively executed while widgets allocate their children.
152 * Each widget, once allocated a size, will go on to first share the
153 * space in one orientation among its children and then request each child's
154 * height for its target allocated width or its width for allocated height,
155 * depending. In this way a `GtkWidget` will typically be requested its size
156 * a number of times before actually being allocated a size. The size a
157 * widget is finally allocated can of course differ from the size it has
158 * requested. For this reason, `GtkWidget` caches a small number of results
159 * to avoid re-querying for the same sizes in one allocation cycle.
160 *
161 * If a widget does move content around to intelligently use up the
162 * allocated size then it must support the request in both
163 * `GtkSizeRequestMode`s even if the widget in question only
164 * trades sizes in a single orientation.
165 *
166 * For instance, a [class@Gtk.Label] that does height-for-width word wrapping
167 * will not expect to have [vfunc@Gtk.Widget.measure] with an orientation of
168 * %GTK_ORIENTATION_VERTICAL called because that call is specific to a
169 * width-for-height request. In this case the label must return the height
170 * required for its own minimum possible width. By following this rule any
171 * widget that handles height-for-width or width-for-height requests will
172 * always be allocated at least enough space to fit its own content.
173 *
174 * Here are some examples of how a %GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH widget
175 * generally deals with width-for-height requests:
176 *
177 * ```c
178 * static void
179 * foo_widget_measure (GtkWidget *widget,
180 * GtkOrientation orientation,
181 * int for_size,
182 * int *minimum_size,
183 * int *natural_size,
184 * int *minimum_baseline,
185 * int *natural_baseline)
186 * {
187 * if (orientation == GTK_ORIENTATION_HORIZONTAL)
188 * {
189 * // Calculate minimum and natural width
190 * }
191 * else // VERTICAL
192 * {
193 * if (i_am_in_height_for_width_mode)
194 * {
195 * int min_width, dummy;
196 *
197 * // First, get the minimum width of our widget
198 * GTK_WIDGET_GET_CLASS (widget)->measure (widget, GTK_ORIENTATION_HORIZONTAL, -1,
199 * &min_width, &dummy, &dummy, &dummy);
200 *
201 * // Now use the minimum width to retrieve the minimum and natural height to display
202 * // that width.
203 * GTK_WIDGET_GET_CLASS (widget)->measure (widget, GTK_ORIENTATION_VERTICAL, min_width,
204 * minimum_size, natural_size, &dummy, &dummy);
205 * }
206 * else
207 * {
208 * // ... some widgets do both.
209 * }
210 * }
211 * }
212 * ```
213 *
214 * Often a widget needs to get its own request during size request or
215 * allocation. For example, when computing height it may need to also
216 * compute width. Or when deciding how to use an allocation, the widget
217 * may need to know its natural size. In these cases, the widget should
218 * be careful to call its virtual methods directly, like in the code
219 * example above.
220 *
221 * It will not work to use the wrapper function [method@Gtk.Widget.measure]
222 * inside your own [vfunc@Gtk.Widget.size_allocate] implementation.
223 * These return a request adjusted by [class@Gtk.SizeGroup], the widget's
224 * align and expand flags, as well as its CSS style.
225 *
226 * If a widget used the wrappers inside its virtual method implementations,
227 * then the adjustments (such as widget margins) would be applied
228 * twice. GTK therefore does not allow this and will warn if you try
229 * to do it.
230 *
231 * Of course if you are getting the size request for another widget, such
232 * as a child widget, you must use [id@gtk_widget_measure]; otherwise, you
233 * would not properly consider widget margins, [class@Gtk.SizeGroup], and
234 * so forth.
235 *
236 * GTK also supports baseline vertical alignment of widgets. This
237 * means that widgets are positioned such that the typographical baseline of
238 * widgets in the same row are aligned. This happens if a widget supports
239 * baselines, has a vertical alignment of %GTK_ALIGN_BASELINE, and is inside
240 * a widget that supports baselines and has a natural “row” that it aligns to
241 * the baseline, or a baseline assigned to it by the grandparent.
242 *
243 * Baseline alignment support for a widget is also done by the
244 * [vfunc@Gtk.Widget.measure] virtual function. It allows you to report
245 * both a minimum and natural size.
246 *
247 * If a widget ends up baseline aligned it will be allocated all the space in
248 * the parent as if it was %GTK_ALIGN_FILL, but the selected baseline can be
249 * found via [id@gtk_widget_get_allocated_baseline]. If the baseline has a
250 * value other than -1 you need to align the widget such that the baseline
251 * appears at the position.
252 *
253 * ### GtkWidget as GtkBuildable
254 *
255 * The `GtkWidget` implementation of the `GtkBuildable` interface
256 * supports various custom elements to specify additional aspects of widgets
257 * that are not directly expressed as properties.
258 *
259 * If the widget uses a [class@Gtk.LayoutManager], `GtkWidget` supports
260 * a custom `<layout>` element, used to define layout properties:
261 *
262 * ```xml
263 * <object class="GtkGrid" id="my_grid">
264 * <child>
265 * <object class="GtkLabel" id="label1">
266 * <property name="label">Description</property>
267 * <layout>
268 * <property name="column">0</property>
269 * <property name="row">0</property>
270 * <property name="row-span">1</property>
271 * <property name="column-span">1</property>
272 * </layout>
273 * </object>
274 * </child>
275 * <child>
276 * <object class="GtkEntry" id="description_entry">
277 * <layout>
278 * <property name="column">1</property>
279 * <property name="row">0</property>
280 * <property name="row-span">1</property>
281 * <property name="column-span">1</property>
282 * </layout>
283 * </object>
284 * </child>
285 * </object>
286 * ```
287 *
288 * `GtkWidget` allows style information such as style classes to
289 * be associated with widgets, using the custom `<style>` element:
290 *
291 * ```xml
292 * <object class="GtkButton" id="button1">
293 * <style>
294 * <class name="my-special-button-class"/>
295 * <class name="dark-button"/>
296 * </style>
297 * </object>
298 * ```
299 *
300 * `GtkWidget` allows defining accessibility information, such as properties,
301 * relations, and states, using the custom `<accessibility>` element:
302 *
303 * ```xml
304 * <object class="GtkButton" id="button1">
305 * <accessibility>
306 * <property name="label">Download</property>
307 * <relation name="labelled-by">label1</relation>
308 * </accessibility>
309 * </object>
310 * ```
311 *
312 * ### Building composite widgets from template XML
313 *
314 * `GtkWidget `exposes some facilities to automate the procedure
315 * of creating composite widgets using "templates".
316 *
317 * To create composite widgets with `GtkBuilder` XML, one must associate
318 * the interface description with the widget class at class initialization
319 * time using [method@Gtk.WidgetClass.set_template].
320 *
321 * The interface description semantics expected in composite template descriptions
322 * is slightly different from regular [class@Gtk.Builder] XML.
323 *
324 * Unlike regular interface descriptions, [method@Gtk.WidgetClass.set_template] will
325 * expect a `<template>` tag as a direct child of the toplevel `<interface>`
326 * tag. The `<template>` tag must specify the “class” attribute which must be
327 * the type name of the widget. Optionally, the “parent” attribute may be
328 * specified to specify the direct parent type of the widget type, this is
329 * ignored by `GtkBuilder` but required for UI design tools like
330 * [Glade](https://glade.gnome.org/) to introspect what kind of properties and
331 * internal children exist for a given type when the actual type does not exist.
332 *
333 * The XML which is contained inside the `<template>` tag behaves as if it were
334 * added to the `<object>` tag defining the widget itself. You may set properties
335 * on a widget by inserting `<property>` tags into the `<template>` tag, and also
336 * add `<child>` tags to add children and extend a widget in the normal way you
337 * would with `<object>` tags.
338 *
339 * Additionally, `<object>` tags can also be added before and after the initial
340 * `<template>` tag in the normal way, allowing one to define auxiliary objects
341 * which might be referenced by other widgets declared as children of the
342 * `<template>` tag.
343 *
344 * An example of a template definition:
345 *
346 * ```xml
347 * <interface>
348 * <template class="FooWidget" parent="GtkBox">
349 * <property name="orientation">horizontal</property>
350 * <property name="spacing">4</property>
351 * <child>
352 * <object class="GtkButton" id="hello_button">
353 * <property name="label">Hello World</property>
354 * <signal name="clicked" handler="hello_button_clicked" object="FooWidget" swapped="yes"/>
355 * </object>
356 * </child>
357 * <child>
358 * <object class="GtkButton" id="goodbye_button">
359 * <property name="label">Goodbye World</property>
360 * </object>
361 * </child>
362 * </template>
363 * </interface>
364 * ```
365 *
366 * Typically, you'll place the template fragment into a file that is
367 * bundled with your project, using `GResource`. In order to load the
368 * template, you need to call [method@Gtk.WidgetClass.set_template_from_resource]
369 * from the class initialization of your `GtkWidget` type:
370 *
371 * ```c
372 * static void
373 * foo_widget_class_init (FooWidgetClass *klass)
374 * {
375 * // ...
376 *
377 * gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (klass),
378 * "/com/example/ui/foowidget.ui");
379 * }
380 * ```
381 *
382 * You will also need to call [method@Gtk.Widget.init_template] from the
383 * instance initialization function:
384 *
385 * ```c
386 * static void
387 * foo_widget_init (FooWidget *self)
388 * {
389 * // ...
390 * gtk_widget_init_template (GTK_WIDGET (self));
391 * }
392 * ```
393 *
394 * You can access widgets defined in the template using the
395 * [id@gtk_widget_get_template_child] function, but you will typically declare
396 * a pointer in the instance private data structure of your type using the same
397 * name as the widget in the template definition, and call
398 * [method@Gtk.WidgetClass.bind_template_child_full] (or one of its wrapper macros
399 * [func@Gtk.widget_class_bind_template_child] and [func@Gtk.widget_class_bind_template_child_private])
400 * with that name, e.g.
401 *
402 * ```c
403 * typedef struct {
404 * GtkWidget *hello_button;
405 * GtkWidget *goodbye_button;
406 * } FooWidgetPrivate;
407 *
408 * G_DEFINE_TYPE_WITH_PRIVATE (FooWidget, foo_widget, GTK_TYPE_BOX)
409 *
410 * static void
411 * foo_widget_class_init (FooWidgetClass *klass)
412 * {
413 * // ...
414 * gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (klass),
415 * "/com/example/ui/foowidget.ui");
416 * gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass),
417 * FooWidget, hello_button);
418 * gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass),
419 * FooWidget, goodbye_button);
420 * }
421 *
422 * static void
423 * foo_widget_init (FooWidget *widget)
424 * {
425 *
426 * }
427 * ```
428 *
429 * You can also use [method@Gtk.WidgetClass.bind_template_callback_full] (or
430 * is wrapper macro [func@Gtk.widget_class_bind_template_callback]) to connect
431 * a signal callback defined in the template with a function visible in the
432 * scope of the class, e.g.
433 *
434 * ```c
435 * // the signal handler has the instance and user data swapped
436 * // because of the swapped="yes" attribute in the template XML
437 * static void
438 * hello_button_clicked (FooWidget *self,
439 * GtkButton *button)
440 * {
441 * g_print ("Hello, world!\n");
442 * }
443 *
444 * static void
445 * foo_widget_class_init (FooWidgetClass *klass)
446 * {
447 * // ...
448 * gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (klass),
449 * "/com/example/ui/foowidget.ui");
450 * gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (klass), hello_button_clicked);
451 * }
452 * ```
453 */
454
455#define GTK_STATE_FLAGS_DO_SET_PROPAGATE (GTK_STATE_FLAG_INSENSITIVE | \
456 GTK_STATE_FLAG_BACKDROP)
457#define GTK_STATE_FLAGS_DO_UNSET_PROPAGATE (GTK_STATE_FLAG_INSENSITIVE | \
458 GTK_STATE_FLAG_BACKDROP | \
459 GTK_STATE_FLAG_PRELIGHT | \
460 GTK_STATE_FLAG_ACTIVE)
461
462typedef struct {
463 char *name; /* Name of the template automatic child */
464 gboolean internal_child; /* Whether the automatic widget should be exported as an <internal-child> */
465 gssize offset; /* Instance private data offset where to set the automatic child (or 0) */
466} AutomaticChildClass;
467
468enum {
469 DESTROY,
470 SHOW,
471 HIDE,
472 MAP,
473 UNMAP,
474 REALIZE,
475 UNREALIZE,
476 STATE_FLAGS_CHANGED,
477 DIRECTION_CHANGED,
478 MNEMONIC_ACTIVATE,
479 MOVE_FOCUS,
480 KEYNAV_FAILED,
481 QUERY_TOOLTIP,
482 LAST_SIGNAL
483};
484
485enum {
486 PROP_0,
487 PROP_NAME,
488 PROP_PARENT,
489 PROP_ROOT,
490 PROP_WIDTH_REQUEST,
491 PROP_HEIGHT_REQUEST,
492 PROP_VISIBLE,
493 PROP_SENSITIVE,
494 PROP_CAN_FOCUS,
495 PROP_HAS_FOCUS,
496 PROP_CAN_TARGET,
497 PROP_FOCUS_ON_CLICK,
498 PROP_FOCUSABLE,
499 PROP_HAS_DEFAULT,
500 PROP_RECEIVES_DEFAULT,
501 PROP_CURSOR,
502 PROP_HAS_TOOLTIP,
503 PROP_TOOLTIP_MARKUP,
504 PROP_TOOLTIP_TEXT,
505 PROP_OPACITY,
506 PROP_OVERFLOW,
507 PROP_HALIGN,
508 PROP_VALIGN,
509 PROP_MARGIN_START,
510 PROP_MARGIN_END,
511 PROP_MARGIN_TOP,
512 PROP_MARGIN_BOTTOM,
513 PROP_HEXPAND,
514 PROP_VEXPAND,
515 PROP_HEXPAND_SET,
516 PROP_VEXPAND_SET,
517 PROP_SCALE_FACTOR,
518 PROP_CSS_NAME,
519 PROP_CSS_CLASSES,
520 PROP_LAYOUT_MANAGER,
521 NUM_PROPERTIES,
522
523 /* GtkAccessible */
524 PROP_ACCESSIBLE_ROLE
525};
526
527
528typedef struct
529{
530 guint flags_to_set;
531 guint flags_to_unset;
532
533 int old_scale_factor;
534} GtkStateData;
535
536
537static void gtk_widget_base_class_init (gpointer g_class);
538static void gtk_widget_class_init (GtkWidgetClass *klass);
539static void gtk_widget_base_class_finalize (GtkWidgetClass *klass);
540static void gtk_widget_init (GTypeInstance *instance,
541 gpointer g_class);
542static void gtk_widget_dispose (GObject *object);
543static void gtk_widget_finalize (GObject *object);
544static void gtk_widget_real_destroy (GtkWidget *object);
545static gboolean gtk_widget_real_focus (GtkWidget *widget,
546 GtkDirectionType direction);
547static void gtk_widget_real_show (GtkWidget *widget);
548static void gtk_widget_real_hide (GtkWidget *widget);
549static void gtk_widget_real_map (GtkWidget *widget);
550static void gtk_widget_real_unmap (GtkWidget *widget);
551static void gtk_widget_real_realize (GtkWidget *widget);
552static void gtk_widget_real_unrealize (GtkWidget *widget);
553static void gtk_widget_real_direction_changed (GtkWidget *widget,
554 GtkTextDirection previous_direction);
555static void gtk_widget_real_css_changed (GtkWidget *widget,
556 GtkCssStyleChange *change);
557static void gtk_widget_real_system_setting_changed (GtkWidget *widget,
558 GtkSystemSetting setting);
559static void gtk_widget_real_set_focus_child (GtkWidget *widget,
560 GtkWidget *child);
561static void gtk_widget_real_move_focus (GtkWidget *widget,
562 GtkDirectionType direction);
563static gboolean gtk_widget_real_keynav_failed (GtkWidget *widget,
564 GtkDirectionType direction);
565#ifdef G_ENABLE_CONSISTENCY_CHECKS
566static void gtk_widget_verify_invariants (GtkWidget *widget);
567static void gtk_widget_push_verify_invariants (GtkWidget *widget);
568static void gtk_widget_pop_verify_invariants (GtkWidget *widget);
569#else
570#define gtk_widget_verify_invariants(widget)
571#define gtk_widget_push_verify_invariants(widget)
572#define gtk_widget_pop_verify_invariants(widget)
573#endif
574static PangoContext* gtk_widget_peek_pango_context (GtkWidget *widget);
575static void gtk_widget_update_default_pango_context (GtkWidget *widget);
576static void gtk_widget_propagate_state (GtkWidget *widget,
577 const GtkStateData *data);
578static gboolean gtk_widget_real_mnemonic_activate (GtkWidget *widget,
579 gboolean group_cycling);
580static void gtk_widget_accessible_interface_init (GtkAccessibleInterface *iface);
581static void gtk_widget_buildable_interface_init (GtkBuildableIface *iface);
582static void gtk_widget_buildable_set_id (GtkBuildable *buildable,
583 const char *id);
584static const char * gtk_widget_buildable_get_id (GtkBuildable *buildable);
585static GObject * gtk_widget_buildable_get_internal_child (GtkBuildable *buildable,
586 GtkBuilder *builder,
587 const char *childname);
588static gboolean gtk_widget_buildable_custom_tag_start (GtkBuildable *buildable,
589 GtkBuilder *builder,
590 GObject *child,
591 const char *tagname,
592 GtkBuildableParser *parser,
593 gpointer *data);
594static void gtk_widget_buildable_custom_tag_end (GtkBuildable *buildable,
595 GtkBuilder *builder,
596 GObject *child,
597 const char *tagname,
598 gpointer data);
599static void gtk_widget_buildable_custom_finished (GtkBuildable *buildable,
600 GtkBuilder *builder,
601 GObject *child,
602 const char *tagname,
603 gpointer data);
604static void gtk_widget_buildable_parser_finished (GtkBuildable *buildable,
605 GtkBuilder *builder);
606static void gtk_widget_set_usize_internal (GtkWidget *widget,
607 int width,
608 int height);
609
610static void remove_parent_surface_transform_changed_listener (GtkWidget *widget);
611static void add_parent_surface_transform_changed_listener (GtkWidget *widget);
612static void gtk_widget_queue_compute_expand (GtkWidget *widget);
613
614
615
616static int GtkWidget_private_offset = 0;
617static gpointer gtk_widget_parent_class = NULL;
618static guint widget_signals[LAST_SIGNAL] = { 0 };
619static GParamSpec *widget_props[NUM_PROPERTIES] = { NULL, };
620GtkTextDirection gtk_default_direction = GTK_TEXT_DIR_LTR;
621
622static GQuark quark_pango_context = 0;
623static GQuark quark_mnemonic_labels = 0;
624static GQuark quark_size_groups = 0;
625static GQuark quark_auto_children = 0;
626static GQuark quark_font_options = 0;
627static GQuark quark_font_map = 0;
628static GQuark quark_builder_set_id = 0;
629
630GType
631gtk_widget_get_type (void)
632{
633 static GType widget_type = 0;
634
635 if (G_UNLIKELY (widget_type == 0))
636 {
637 const GTypeInfo widget_info =
638 {
639 sizeof (GtkWidgetClass),
640 gtk_widget_base_class_init,
641 (GBaseFinalizeFunc) gtk_widget_base_class_finalize,
642 (GClassInitFunc) gtk_widget_class_init,
643 NULL, /* class_finalize */
644 NULL, /* class_init */
645 sizeof (GtkWidget),
646 0, /* n_preallocs */
647 gtk_widget_init,
648 NULL, /* value_table */
649 };
650
651 const GInterfaceInfo accessible_info =
652 {
653 (GInterfaceInitFunc) gtk_widget_accessible_interface_init,
654 (GInterfaceFinalizeFunc) NULL,
655 NULL,
656 };
657
658 const GInterfaceInfo buildable_info =
659 {
660 (GInterfaceInitFunc) gtk_widget_buildable_interface_init,
661 (GInterfaceFinalizeFunc) NULL,
662 NULL /* interface data */
663 };
664
665 const GInterfaceInfo constraint_target_info =
666 {
667 (GInterfaceInitFunc) NULL,
668 (GInterfaceFinalizeFunc) NULL,
669 NULL /* interface data */
670 };
671
672 widget_type = g_type_register_static (G_TYPE_INITIALLY_UNOWNED, type_name: g_intern_static_string (string: "GtkWidget"),
673 info: &widget_info, flags: G_TYPE_FLAG_ABSTRACT);
674
675 g_type_add_class_private (class_type: widget_type, private_size: sizeof (GtkWidgetClassPrivate));
676
677 GtkWidget_private_offset = g_type_add_instance_private (class_type: widget_type, private_size: sizeof (GtkWidgetPrivate));
678
679 g_type_add_interface_static (instance_type: widget_type, GTK_TYPE_ACCESSIBLE,
680 info: &accessible_info);
681 g_type_add_interface_static (instance_type: widget_type, GTK_TYPE_BUILDABLE,
682 info: &buildable_info);
683 g_type_add_interface_static (instance_type: widget_type, GTK_TYPE_CONSTRAINT_TARGET,
684 info: &constraint_target_info);
685 }
686
687 return widget_type;
688}
689
690static inline gpointer
691gtk_widget_get_instance_private (GtkWidget *self)
692{
693 return (G_STRUCT_MEMBER_P (self, GtkWidget_private_offset));
694}
695
696static void
697gtk_widget_base_class_init (gpointer g_class)
698{
699 GtkWidgetClass *klass = g_class;
700 GtkWidgetClassPrivate *priv;
701
702 priv = klass->priv = G_TYPE_CLASS_GET_PRIVATE (g_class, GTK_TYPE_WIDGET, GtkWidgetClassPrivate);
703
704 priv->template = NULL;
705
706 if (priv->shortcuts == NULL)
707 {
708 priv->shortcuts = g_list_store_new (GTK_TYPE_SHORTCUT);
709 }
710 else
711 {
712 GListModel *parent_shortcuts = G_LIST_MODEL (ptr: priv->shortcuts);
713 guint i, p;
714
715 priv->shortcuts = g_list_store_new (GTK_TYPE_SHORTCUT);
716 for (i = 0, p = g_list_model_get_n_items (list: parent_shortcuts); i < p; i++)
717 {
718 GtkShortcut *shortcut = g_list_model_get_item (list: parent_shortcuts, position: i);
719 g_list_store_append (store: priv->shortcuts, item: shortcut);
720 g_object_unref (object: shortcut);
721 }
722 }
723}
724
725static void
726gtk_widget_real_snapshot (GtkWidget *widget,
727 GtkSnapshot *snapshot)
728{
729 GtkWidget *child;
730
731 for (child = _gtk_widget_get_first_child (widget);
732 child != NULL;
733 child = _gtk_widget_get_next_sibling (widget: child))
734 gtk_widget_snapshot_child (widget, child, snapshot);
735}
736
737static gboolean
738gtk_widget_real_contains (GtkWidget *widget,
739 double x,
740 double y)
741{
742 GtkCssBoxes boxes;
743
744 gtk_css_boxes_init (boxes: &boxes, widget);
745
746 return gsk_rounded_rect_contains_point (self: gtk_css_boxes_get_border_box (boxes: &boxes),
747 point: &GRAPHENE_POINT_INIT (x, y));
748}
749
750static void
751gtk_widget_real_root (GtkWidget *widget)
752{
753 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
754 GList *l;
755
756 gtk_widget_forall (widget, callback: (GtkCallback) gtk_widget_root, NULL);
757
758 for (l = priv->event_controllers; l; l = l->next)
759 {
760 if (GTK_IS_SHORTCUT_CONTROLLER (l->data))
761 gtk_shortcut_controller_root (GTK_SHORTCUT_CONTROLLER (l->data));
762 }
763}
764
765static void
766gtk_widget_real_unroot (GtkWidget *widget)
767{
768 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
769 GList *l;
770
771 for (l = priv->event_controllers; l; l = l->next)
772 {
773 if (GTK_IS_SHORTCUT_CONTROLLER (l->data))
774 gtk_shortcut_controller_unroot (GTK_SHORTCUT_CONTROLLER (l->data));
775 }
776
777 gtk_widget_forall (widget, callback: (GtkCallback) gtk_widget_unroot, NULL);
778}
779
780static void
781gtk_widget_constructed (GObject *object)
782{
783 G_OBJECT_CLASS (gtk_widget_parent_class)->constructed (object);
784
785 if (GTK_WIDGET_GET_CLASS (object)->priv->actions)
786 {
787 GtkActionMuxer *muxer;
788
789 muxer = _gtk_widget_get_action_muxer (GTK_WIDGET (object), TRUE);
790 gtk_action_muxer_connect_class_actions (muxer);
791 }
792}
793
794static void
795gtk_widget_real_measure (GtkWidget *widget,
796 GtkOrientation orientation,
797 int for_size,
798 int *minimum,
799 int *natural,
800 int *minimum_baseline,
801 int *natural_baseline)
802{
803 *minimum = 0;
804 *natural = 0;
805}
806
807static GtkSizeRequestMode
808gtk_widget_real_get_request_mode (GtkWidget *widget)
809{
810 /* By default widgets don't trade size at all. */
811 return GTK_SIZE_REQUEST_CONSTANT_SIZE;
812}
813
814static void
815gtk_widget_real_state_flags_changed (GtkWidget *widget,
816 GtkStateFlags old_state)
817{
818}
819
820static gboolean
821gtk_widget_real_query_tooltip (GtkWidget *widget,
822 int x,
823 int y,
824 gboolean keyboard_tip,
825 GtkTooltip *tooltip)
826{
827 const char *tooltip_markup;
828 gboolean has_tooltip;
829
830 has_tooltip = gtk_widget_get_has_tooltip (widget);
831 tooltip_markup = gtk_widget_get_tooltip_markup (widget);
832 if (tooltip_markup == NULL)
833 tooltip_markup = gtk_widget_get_tooltip_text (widget);
834
835 if (has_tooltip && tooltip_markup != NULL)
836 {
837 gtk_tooltip_set_markup (tooltip, markup: tooltip_markup);
838 return TRUE;
839 }
840
841 return FALSE;
842}
843
844static void
845gtk_widget_real_size_allocate (GtkWidget *widget,
846 int width,
847 int height,
848 int baseline)
849{
850}
851
852static void
853gtk_widget_set_accessible_role (GtkWidget *self,
854 GtkAccessibleRole role)
855{
856 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self);
857
858 if (priv->at_context == NULL || !gtk_at_context_is_realized (self: priv->at_context))
859 {
860 priv->accessible_role = role;
861
862 if (priv->at_context != NULL)
863 gtk_at_context_set_accessible_role (self: priv->at_context, role);
864
865 g_object_notify (G_OBJECT (self), property_name: "accessible-role");
866 }
867 else
868 {
869 char *role_str = g_enum_to_string (g_enum_type: GTK_TYPE_ACCESSIBLE_ROLE, value: priv->accessible_role);
870
871 g_critical ("Widget of type “%s” already has an accessible role of type “%s”",
872 G_OBJECT_TYPE_NAME (self),
873 role_str);
874 g_free (mem: role_str);
875 }
876}
877
878static GtkAccessibleRole
879gtk_widget_get_accessible_role (GtkWidget *self)
880{
881 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self);
882 GtkATContext *context = gtk_accessible_get_at_context (self: GTK_ACCESSIBLE (ptr: self));
883 GtkWidgetClassPrivate *class_priv;
884
885 if (context != NULL && gtk_at_context_is_realized (self: context))
886 return gtk_at_context_get_accessible_role (self: context);
887
888 if (priv->accessible_role != GTK_ACCESSIBLE_ROLE_WIDGET)
889 return priv->accessible_role;
890
891 class_priv = GTK_WIDGET_GET_CLASS (self)->priv;
892
893 return class_priv->accessible_role;
894}
895
896static void
897gtk_widget_set_property (GObject *object,
898 guint prop_id,
899 const GValue *value,
900 GParamSpec *pspec)
901{
902 GtkWidget *widget = GTK_WIDGET (object);
903 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
904
905 switch (prop_id)
906 {
907 case PROP_NAME:
908 gtk_widget_set_name (widget, name: g_value_get_string (value));
909 break;
910 case PROP_WIDTH_REQUEST:
911 gtk_widget_set_usize_internal (widget, width: g_value_get_int (value), height: -2);
912 break;
913 case PROP_HEIGHT_REQUEST:
914 gtk_widget_set_usize_internal (widget, width: -2, height: g_value_get_int (value));
915 break;
916 case PROP_VISIBLE:
917 gtk_widget_set_visible (widget, visible: g_value_get_boolean (value));
918 break;
919 case PROP_SENSITIVE:
920 gtk_widget_set_sensitive (widget, sensitive: g_value_get_boolean (value));
921 break;
922 case PROP_CAN_FOCUS:
923 gtk_widget_set_can_focus (widget, can_focus: g_value_get_boolean (value));
924 break;
925 case PROP_FOCUSABLE:
926 gtk_widget_set_focusable (widget, focusable: g_value_get_boolean (value));
927 break;
928 case PROP_CAN_TARGET:
929 gtk_widget_set_can_target (widget, can_target: g_value_get_boolean (value));
930 break;
931 case PROP_FOCUS_ON_CLICK:
932 gtk_widget_set_focus_on_click (widget, focus_on_click: g_value_get_boolean (value));
933 break;
934 case PROP_RECEIVES_DEFAULT:
935 gtk_widget_set_receives_default (widget, receives_default: g_value_get_boolean (value));
936 break;
937 case PROP_CURSOR:
938 gtk_widget_set_cursor (widget, cursor: g_value_get_object (value));
939 break;
940 case PROP_HAS_TOOLTIP:
941 gtk_widget_set_has_tooltip (widget, has_tooltip: g_value_get_boolean (value));
942 break;
943 case PROP_TOOLTIP_MARKUP:
944 gtk_widget_set_tooltip_markup (widget, markup: g_value_get_string (value));
945 break;
946 case PROP_TOOLTIP_TEXT:
947 gtk_widget_set_tooltip_text (widget, text: g_value_get_string (value));
948 break;
949 case PROP_HALIGN:
950 gtk_widget_set_halign (widget, align: g_value_get_enum (value));
951 break;
952 case PROP_VALIGN:
953 gtk_widget_set_valign (widget, align: g_value_get_enum (value));
954 break;
955 case PROP_MARGIN_START:
956 gtk_widget_set_margin_start (widget, margin: g_value_get_int (value));
957 break;
958 case PROP_MARGIN_END:
959 gtk_widget_set_margin_end (widget, margin: g_value_get_int (value));
960 break;
961 case PROP_MARGIN_TOP:
962 gtk_widget_set_margin_top (widget, margin: g_value_get_int (value));
963 break;
964 case PROP_MARGIN_BOTTOM:
965 gtk_widget_set_margin_bottom (widget, margin: g_value_get_int (value));
966 break;
967 case PROP_HEXPAND:
968 gtk_widget_set_hexpand (widget, expand: g_value_get_boolean (value));
969 break;
970 case PROP_HEXPAND_SET:
971 gtk_widget_set_hexpand_set (widget, set: g_value_get_boolean (value));
972 break;
973 case PROP_VEXPAND:
974 gtk_widget_set_vexpand (widget, expand: g_value_get_boolean (value));
975 break;
976 case PROP_VEXPAND_SET:
977 gtk_widget_set_vexpand_set (widget, set: g_value_get_boolean (value));
978 break;
979 case PROP_OPACITY:
980 gtk_widget_set_opacity (widget, opacity: g_value_get_double (value));
981 break;
982 case PROP_OVERFLOW:
983 gtk_widget_set_overflow (widget, overflow: g_value_get_enum (value));
984 break;
985 case PROP_CSS_NAME:
986 if (g_value_get_string (value) != NULL)
987 gtk_css_node_set_name (cssnode: priv->cssnode, name: g_quark_from_string (string: g_value_get_string (value)));
988 break;
989 case PROP_CSS_CLASSES:
990 gtk_widget_set_css_classes (widget, classes: g_value_get_boxed (value));
991 break;
992 case PROP_LAYOUT_MANAGER:
993 gtk_widget_set_layout_manager (widget, layout_manager: g_value_dup_object (value));
994 break;
995 case PROP_ACCESSIBLE_ROLE:
996 gtk_widget_set_accessible_role (self: widget, role: g_value_get_enum (value));
997 break;
998 default:
999 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1000 break;
1001 }
1002}
1003
1004static void
1005gtk_widget_get_property (GObject *object,
1006 guint prop_id,
1007 GValue *value,
1008 GParamSpec *pspec)
1009{
1010 GtkWidget *widget = GTK_WIDGET (object);
1011 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
1012
1013 switch (prop_id)
1014 {
1015 case PROP_NAME:
1016 if (priv->name)
1017 g_value_set_string (value, v_string: priv->name);
1018 else
1019 g_value_set_static_string (value, v_string: "");
1020 break;
1021 case PROP_PARENT:
1022 g_value_set_object (value, v_object: priv->parent);
1023 break;
1024 case PROP_ROOT:
1025 g_value_set_object (value, v_object: priv->root);
1026 break;
1027 case PROP_WIDTH_REQUEST:
1028 {
1029 int w;
1030 gtk_widget_get_size_request (widget, width: &w, NULL);
1031 g_value_set_int (value, v_int: w);
1032 }
1033 break;
1034 case PROP_HEIGHT_REQUEST:
1035 {
1036 int h;
1037 gtk_widget_get_size_request (widget, NULL, height: &h);
1038 g_value_set_int (value, v_int: h);
1039 }
1040 break;
1041 case PROP_VISIBLE:
1042 g_value_set_boolean (value, v_boolean: _gtk_widget_get_visible (widget));
1043 break;
1044 case PROP_SENSITIVE:
1045 g_value_set_boolean (value, v_boolean: gtk_widget_get_sensitive (widget));
1046 break;
1047 case PROP_CAN_FOCUS:
1048 g_value_set_boolean (value, v_boolean: gtk_widget_get_can_focus (widget));
1049 break;
1050 case PROP_FOCUSABLE:
1051 g_value_set_boolean (value, v_boolean: gtk_widget_get_focusable (widget));
1052 break;
1053 case PROP_HAS_FOCUS:
1054 g_value_set_boolean (value, v_boolean: gtk_widget_has_focus (widget));
1055 break;
1056 case PROP_CAN_TARGET:
1057 g_value_set_boolean (value, v_boolean: gtk_widget_get_can_target (widget));
1058 break;
1059 case PROP_FOCUS_ON_CLICK:
1060 g_value_set_boolean (value, v_boolean: gtk_widget_get_focus_on_click (widget));
1061 break;
1062 case PROP_HAS_DEFAULT:
1063 g_value_set_boolean (value, v_boolean: gtk_widget_has_default (widget));
1064 break;
1065 case PROP_RECEIVES_DEFAULT:
1066 g_value_set_boolean (value, v_boolean: gtk_widget_get_receives_default (widget));
1067 break;
1068 case PROP_CURSOR:
1069 g_value_set_object (value, v_object: gtk_widget_get_cursor (widget));
1070 break;
1071 case PROP_HAS_TOOLTIP:
1072 g_value_set_boolean (value, v_boolean: gtk_widget_get_has_tooltip (widget));
1073 break;
1074 case PROP_TOOLTIP_TEXT:
1075 g_value_set_string (value, v_string: gtk_widget_get_tooltip_text (widget));
1076 break;
1077 case PROP_TOOLTIP_MARKUP:
1078 g_value_set_string (value, v_string: gtk_widget_get_tooltip_markup (widget));
1079 break;
1080 case PROP_HALIGN:
1081 g_value_set_enum (value, v_enum: gtk_widget_get_halign (widget));
1082 break;
1083 case PROP_VALIGN:
1084 g_value_set_enum (value, v_enum: gtk_widget_get_valign (widget));
1085 break;
1086 case PROP_MARGIN_START:
1087 g_value_set_int (value, v_int: gtk_widget_get_margin_start (widget));
1088 break;
1089 case PROP_MARGIN_END:
1090 g_value_set_int (value, v_int: gtk_widget_get_margin_end (widget));
1091 break;
1092 case PROP_MARGIN_TOP:
1093 g_value_set_int (value, v_int: gtk_widget_get_margin_top (widget));
1094 break;
1095 case PROP_MARGIN_BOTTOM:
1096 g_value_set_int (value, v_int: gtk_widget_get_margin_bottom (widget));
1097 break;
1098 case PROP_HEXPAND:
1099 g_value_set_boolean (value, v_boolean: gtk_widget_get_hexpand (widget));
1100 break;
1101 case PROP_HEXPAND_SET:
1102 g_value_set_boolean (value, v_boolean: gtk_widget_get_hexpand_set (widget));
1103 break;
1104 case PROP_VEXPAND:
1105 g_value_set_boolean (value, v_boolean: gtk_widget_get_vexpand (widget));
1106 break;
1107 case PROP_VEXPAND_SET:
1108 g_value_set_boolean (value, v_boolean: gtk_widget_get_vexpand_set (widget));
1109 break;
1110 case PROP_OPACITY:
1111 g_value_set_double (value, v_double: gtk_widget_get_opacity (widget));
1112 break;
1113 case PROP_OVERFLOW:
1114 g_value_set_enum (value, v_enum: gtk_widget_get_overflow (widget));
1115 break;
1116 case PROP_SCALE_FACTOR:
1117 g_value_set_int (value, v_int: gtk_widget_get_scale_factor (widget));
1118 break;
1119 case PROP_CSS_NAME:
1120 g_value_set_string (value, v_string: gtk_widget_get_css_name (self: widget));
1121 break;
1122 case PROP_CSS_CLASSES:
1123 g_value_take_boxed (value, v_boxed: gtk_widget_get_css_classes (widget));
1124 break;
1125 case PROP_LAYOUT_MANAGER:
1126 g_value_set_object (value, v_object: gtk_widget_get_layout_manager (widget));
1127 break;
1128 case PROP_ACCESSIBLE_ROLE:
1129 g_value_set_enum (value, v_enum: gtk_widget_get_accessible_role (self: widget));
1130 break;
1131 default:
1132 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1133 break;
1134 }
1135}
1136
1137static void
1138gtk_widget_class_init (GtkWidgetClass *klass)
1139{
1140 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1141
1142 g_type_class_adjust_private_offset (g_class: klass, private_size_or_offset: &GtkWidget_private_offset);
1143 gtk_widget_parent_class = g_type_class_peek_parent (g_class: klass);
1144
1145 quark_pango_context = g_quark_from_static_string (string: "gtk-pango-context");
1146 quark_mnemonic_labels = g_quark_from_static_string (string: "gtk-mnemonic-labels");
1147 quark_size_groups = g_quark_from_static_string (string: "gtk-widget-size-groups");
1148 quark_auto_children = g_quark_from_static_string (string: "gtk-widget-auto-children");
1149 quark_font_options = g_quark_from_static_string (string: "gtk-widget-font-options");
1150 quark_font_map = g_quark_from_static_string (string: "gtk-widget-font-map");
1151
1152 gobject_class->constructed = gtk_widget_constructed;
1153 gobject_class->dispose = gtk_widget_dispose;
1154 gobject_class->finalize = gtk_widget_finalize;
1155 gobject_class->set_property = gtk_widget_set_property;
1156 gobject_class->get_property = gtk_widget_get_property;
1157
1158 klass->show = gtk_widget_real_show;
1159 klass->hide = gtk_widget_real_hide;
1160 klass->map = gtk_widget_real_map;
1161 klass->unmap = gtk_widget_real_unmap;
1162 klass->realize = gtk_widget_real_realize;
1163 klass->unrealize = gtk_widget_real_unrealize;
1164 klass->root = gtk_widget_real_root;
1165 klass->unroot = gtk_widget_real_unroot;
1166 klass->size_allocate = gtk_widget_real_size_allocate;
1167 klass->get_request_mode = gtk_widget_real_get_request_mode;
1168 klass->measure = gtk_widget_real_measure;
1169 klass->state_flags_changed = gtk_widget_real_state_flags_changed;
1170 klass->direction_changed = gtk_widget_real_direction_changed;
1171 klass->snapshot = gtk_widget_real_snapshot;
1172 klass->mnemonic_activate = gtk_widget_real_mnemonic_activate;
1173 klass->grab_focus = gtk_widget_grab_focus_self;
1174 klass->focus = gtk_widget_real_focus;
1175 klass->set_focus_child = gtk_widget_real_set_focus_child;
1176 klass->move_focus = gtk_widget_real_move_focus;
1177 klass->keynav_failed = gtk_widget_real_keynav_failed;
1178 klass->query_tooltip = gtk_widget_real_query_tooltip;
1179 klass->css_changed = gtk_widget_real_css_changed;
1180 klass->system_setting_changed = gtk_widget_real_system_setting_changed;
1181 klass->contains = gtk_widget_real_contains;
1182
1183 /**
1184 * GtkWidget:name: (attributes org.gtk.Property.get=gtk_widget_get_name org.gtk.Property.set=gtk_widget_set_name)
1185 *
1186 * The name of the widget.
1187 */
1188 widget_props[PROP_NAME] =
1189 g_param_spec_string (name: "name",
1190 P_("Widget name"),
1191 P_("The name of the widget"),
1192 NULL,
1193 GTK_PARAM_READWRITE);
1194
1195 /**
1196 * GtkWidget:parent: (attributes org.gtk.Property.get=gtk_widget_get_parent)
1197 *
1198 * The parent widget of this widget.
1199 */
1200 widget_props[PROP_PARENT] =
1201 g_param_spec_object (name: "parent",
1202 P_("Parent widget"),
1203 P_("The parent widget of this widget."),
1204 GTK_TYPE_WIDGET,
1205 GTK_PARAM_READABLE|G_PARAM_EXPLICIT_NOTIFY);
1206
1207 /**
1208 * GtkWidget:root: (attributes org.gtk.Property.get=gtk_widget_get_root)
1209 *
1210 * The `GtkRoot` widget of the widget tree containing this widget.
1211 *
1212 * This will be %NULL if the widget is not contained in a root widget.
1213 */
1214 widget_props[PROP_ROOT] =
1215 g_param_spec_object (name: "root",
1216 P_("Root widget"),
1217 P_("The root widget in the widget tree."),
1218 GTK_TYPE_ROOT,
1219 GTK_PARAM_READABLE|G_PARAM_EXPLICIT_NOTIFY);
1220
1221 /**
1222 * GtkWidget:width-request:
1223 *
1224 * Override for width request of the widget.
1225 *
1226 * If this is -1, the natural request will be used.
1227 */
1228 widget_props[PROP_WIDTH_REQUEST] =
1229 g_param_spec_int (name: "width-request",
1230 P_("Width request"),
1231 P_("Override for width request of the widget, or -1 if natural request should be used"),
1232 minimum: -1, G_MAXINT,
1233 default_value: -1,
1234 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1235
1236 /**
1237 * GtkWidget:height-request:
1238 *
1239 * Override for height request of the widget.
1240 *
1241 * If this is -1, the natural request will be used.
1242 */
1243 widget_props[PROP_HEIGHT_REQUEST] =
1244 g_param_spec_int (name: "height-request",
1245 P_("Height request"),
1246 P_("Override for height request of the widget, or -1 if natural request should be used"),
1247 minimum: -1, G_MAXINT,
1248 default_value: -1,
1249 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1250
1251 /**
1252 * GtkWidget:visible: (attributes org.gtk.Property.get=gtk_widget_get_visible org.gtk.Property.set=gtk_widget_set_visible)
1253 *
1254 * Whether the widget is visible.
1255 */
1256 widget_props[PROP_VISIBLE] =
1257 g_param_spec_boolean (name: "visible",
1258 P_("Visible"),
1259 P_("Whether the widget is visible"),
1260 TRUE,
1261 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1262
1263 /**
1264 * GtkWidget:sensitive: (attributes org.gtk.Property.get=gtk_widget_get_sensitive org.gtk.Property.set=gtk_widget_set_sensitive)
1265 *
1266 * Whether the widget responds to input.
1267 */
1268 widget_props[PROP_SENSITIVE] =
1269 g_param_spec_boolean (name: "sensitive",
1270 P_("Sensitive"),
1271 P_("Whether the widget responds to input"),
1272 TRUE,
1273 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1274
1275 /**
1276 * GtkWidget:can-focus: (attributes org.gtk.Property.get=gtk_widget_get_can_focus org.gtk.Property.set=gtk_widget_set_can_focus)
1277 *
1278 * Whether the widget or any of its descendents can accept
1279 * the input focus.
1280 *
1281 * This property is meant to be set by widget implementations,
1282 * typically in their instance init function.
1283 */
1284 widget_props[PROP_CAN_FOCUS] =
1285 g_param_spec_boolean (name: "can-focus",
1286 P_("Can focus"),
1287 P_("Whether the widget can accept the input focus"),
1288 TRUE,
1289 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1290
1291 /**
1292 * GtkWidget:focusable: (attributes org.gtk.Property.get=gtk_widget_get_focusable org.gtk.Property.set=gtk_widget_set_focusable)
1293 *
1294 * Whether this widget itself will accept the input focus.
1295 */
1296 widget_props[PROP_FOCUSABLE] =
1297 g_param_spec_boolean (name: "focusable",
1298 P_("Focusable"),
1299 P_("Whether the widget can accept the input focus"),
1300 FALSE,
1301 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1302
1303 /**
1304 * GtkWidget:has-focus: (attributes org.gtk.Property.get=gtk_widget_has_focus)
1305 *
1306 * Whether the widget has the input focus.
1307 */
1308 widget_props[PROP_HAS_FOCUS] =
1309 g_param_spec_boolean (name: "has-focus",
1310 P_("Has focus"),
1311 P_("Whether the widget has the input focus"),
1312 FALSE,
1313 GTK_PARAM_READABLE|G_PARAM_EXPLICIT_NOTIFY);
1314
1315 /**
1316 * GtkWidget:can-target: (attributes org.gtk.Property.get=gtk_widget_get_can_target org.gtk.Property.set=gtk_widget_set_can_target)
1317 *
1318 * Whether the widget can receive pointer events.
1319 */
1320 widget_props[PROP_CAN_TARGET] =
1321 g_param_spec_boolean (name: "can-target",
1322 P_("Can target"),
1323 P_("Whether the widget can receive pointer events"),
1324 TRUE,
1325 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1326
1327 /**
1328 * GtkWidget:focus-on-click: (attributes org.gtk.Property.get=gtk_widget_get_focus_on_click org.gtk.Property.set=gtk_widget_set_focus_on_click)
1329 *
1330 * Whether the widget should grab focus when it is clicked with the mouse.
1331 *
1332 * This property is only relevant for widgets that can take focus.
1333 */
1334 widget_props[PROP_FOCUS_ON_CLICK] =
1335 g_param_spec_boolean (name: "focus-on-click",
1336 P_("Focus on click"),
1337 P_("Whether the widget should grab focus when it is clicked with the mouse"),
1338 TRUE,
1339 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1340
1341 /**
1342 * GtkWidget:has-default: (attributes org.gtk.Property.get=gtk_widget_has_default)
1343 *
1344 * Whether the widget is the default widget.
1345 */
1346 widget_props[PROP_HAS_DEFAULT] =
1347 g_param_spec_boolean (name: "has-default",
1348 P_("Has default"),
1349 P_("Whether the widget is the default widget"),
1350 FALSE,
1351 GTK_PARAM_READABLE|G_PARAM_EXPLICIT_NOTIFY);
1352
1353 /**
1354 * GtkWidget:receives-default: (attributes org.gtk.Property.get=gtk_widget_get_receives_default org.gtk.Property.set=gtk_widget_set_receives_default)
1355 *
1356 * Whether the widget will receive the default action when it is focused.
1357 */
1358 widget_props[PROP_RECEIVES_DEFAULT] =
1359 g_param_spec_boolean (name: "receives-default",
1360 P_("Receives default"),
1361 P_("If TRUE, the widget will receive the default action when it is focused"),
1362 FALSE,
1363 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1364
1365/**
1366 * GtkWidget:cursor: (attributes org.gtk.Property.get=gtk_widget_get_cursor org.gtk.Property.set=gtk_widget_set_cursor)
1367 *
1368 * The cursor used by @widget.
1369 */
1370 widget_props[PROP_CURSOR] =
1371 g_param_spec_object(name: "cursor",
1372 P_("Cursor"),
1373 P_("The cursor to show when hovering above widget"),
1374 GDK_TYPE_CURSOR,
1375 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1376
1377/**
1378 * GtkWidget:has-tooltip: (attributes org.gtk.Property.get=gtk_widget_get_has_tooltip org.gtk.Property.set=gtk_widget_set_has_tooltip)
1379 *
1380 * Enables or disables the emission of the ::query-tooltip signal on @widget.
1381 *
1382 * A value of %TRUE indicates that @widget can have a tooltip, in this case
1383 * the widget will be queried using [signal@Gtk.Widget::query-tooltip] to
1384 * determine whether it will provide a tooltip or not.
1385 */
1386 widget_props[PROP_HAS_TOOLTIP] =
1387 g_param_spec_boolean (name: "has-tooltip",
1388 P_("Has tooltip"),
1389 P_("Whether this widget has a tooltip"),
1390 FALSE,
1391 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1392
1393 /**
1394 * GtkWidget:tooltip-text: (attributes org.gtk.Property.get=gtk_widget_get_tooltip_text org.gtk.Property.set=gtk_widget_set_tooltip_text)
1395 *
1396 * Sets the text of tooltip to be the given string.
1397 *
1398 * Also see [method@Gtk.Tooltip.set_text].
1399 *
1400 * This is a convenience property which will take care of getting the
1401 * tooltip shown if the given string is not %NULL:
1402 * [property@Gtk.Widget:has-tooltip] will automatically be set to %TRUE
1403 * and there will be taken care of [signal@Gtk.Widget::query-tooltip] in
1404 * the default signal handler.
1405 *
1406 * Note that if both [property@Gtk.Widget:tooltip-text] and
1407 * [property@Gtk.Widget:tooltip-markup] are set, the last one wins.
1408 */
1409 widget_props[PROP_TOOLTIP_TEXT] =
1410 g_param_spec_string (name: "tooltip-text",
1411 P_("Tooltip Text"),
1412 P_("The contents of the tooltip for this widget"),
1413 NULL,
1414 GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
1415
1416 /**
1417 * GtkWidget:tooltip-markup: (attributes org.gtk.Property.get=gtk_widget_get_tooltip_markup org.gtk.Property.set=gtk_widget_set_tooltip_markup)
1418 *
1419 * Sets the text of tooltip to be the given string, which is marked up
1420 * with Pango markup.
1421 *
1422 * Also see [method@Gtk.Tooltip.set_markup].
1423 *
1424 * This is a convenience property which will take care of getting the
1425 * tooltip shown if the given string is not %NULL:
1426 * [property@Gtk.Widget:has-tooltip] will automatically be set to %TRUE
1427 * and there will be taken care of [signal@Gtk.Widget::query-tooltip] in
1428 * the default signal handler.
1429 *
1430 * Note that if both [property@Gtk.Widget:tooltip-text] and
1431 * [property@Gtk.Widget:tooltip-markup] are set, the last one wins.
1432 */
1433 widget_props[PROP_TOOLTIP_MARKUP] =
1434 g_param_spec_string (name: "tooltip-markup",
1435 P_("Tooltip markup"),
1436 P_("The contents of the tooltip for this widget"),
1437 NULL,
1438 GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
1439
1440 /**
1441 * GtkWidget:halign: (attributes org.gtk.Property.get=gtk_widget_get_halign org.gtk.Property.set=gtk_widget_set_halign)
1442 *
1443 * How to distribute horizontal space if widget gets extra space.
1444 */
1445 widget_props[PROP_HALIGN] =
1446 g_param_spec_enum (name: "halign",
1447 P_("Horizontal Alignment"),
1448 P_("How to position in extra horizontal space"),
1449 enum_type: GTK_TYPE_ALIGN,
1450 default_value: GTK_ALIGN_FILL,
1451 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1452
1453 /**
1454 * GtkWidget:valign: (attributes org.gtk.Property.get=gtk_widget_get_valign org.gtk.Property.set=gtk_widget_set_valign)
1455 *
1456 * How to distribute vertical space if widget gets extra space.
1457 */
1458 widget_props[PROP_VALIGN] =
1459 g_param_spec_enum (name: "valign",
1460 P_("Vertical Alignment"),
1461 P_("How to position in extra vertical space"),
1462 enum_type: GTK_TYPE_ALIGN,
1463 default_value: GTK_ALIGN_FILL,
1464 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1465
1466 /**
1467 * GtkWidget:margin-start: (attributes org.gtk.Property.get=gtk_widget_get_margin_start org.gtk.Property.set=gtk_widget_set_margin_start)
1468 *
1469 * Margin on start of widget, horizontally.
1470 *
1471 * This property supports left-to-right and right-to-left text
1472 * directions.
1473 *
1474 * This property adds margin outside of the widget's normal size
1475 * request, the margin will be added in addition to the size from
1476 * [method@Gtk.Widget.set_size_request] for example.
1477 */
1478 widget_props[PROP_MARGIN_START] =
1479 g_param_spec_int (name: "margin-start",
1480 P_("Margin on Start"),
1481 P_("Pixels of extra space on the start"),
1482 minimum: 0, G_MAXINT16,
1483 default_value: 0,
1484 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1485
1486 /**
1487 * GtkWidget:margin-end: (attributes org.gtk.Property.get=gtk_widget_get_margin_end org.gtk.Property.set=gtk_widget_set_margin_end)
1488 *
1489 * Margin on end of widget, horizontally.
1490 *
1491 * This property supports left-to-right and right-to-left text
1492 * directions.
1493 *
1494 * This property adds margin outside of the widget's normal size
1495 * request, the margin will be added in addition to the size from
1496 * [method@Gtk.Widget.set_size_request] for example.
1497 */
1498 widget_props[PROP_MARGIN_END] =
1499 g_param_spec_int (name: "margin-end",
1500 P_("Margin on End"),
1501 P_("Pixels of extra space on the end"),
1502 minimum: 0, G_MAXINT16,
1503 default_value: 0,
1504 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1505
1506 /**
1507 * GtkWidget:margin-top: (attributes org.gtk.Property.get=gtk_widget_get_margin_top org.gtk.Property.set=gtk_widget_set_margin_top)
1508 *
1509 * Margin on top side of widget.
1510 *
1511 * This property adds margin outside of the widget's normal size
1512 * request, the margin will be added in addition to the size from
1513 * [method@Gtk.Widget.set_size_request] for example.
1514 */
1515 widget_props[PROP_MARGIN_TOP] =
1516 g_param_spec_int (name: "margin-top",
1517 P_("Margin on Top"),
1518 P_("Pixels of extra space on the top side"),
1519 minimum: 0, G_MAXINT16,
1520 default_value: 0,
1521 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1522
1523 /**
1524 * GtkWidget:margin-bottom: (attributes org.gtk.Property.get=gtk_widget_get_margin_bottom org.gtk.Property.set=gtk_widget_set_margin_bottom)
1525 *
1526 * Margin on bottom side of widget.
1527 *
1528 * This property adds margin outside of the widget's normal size
1529 * request, the margin will be added in addition to the size from
1530 * [method@Gtk.Widget.set_size_request] for example.
1531 */
1532 widget_props[PROP_MARGIN_BOTTOM] =
1533 g_param_spec_int (name: "margin-bottom",
1534 P_("Margin on Bottom"),
1535 P_("Pixels of extra space on the bottom side"),
1536 minimum: 0, G_MAXINT16,
1537 default_value: 0,
1538 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1539
1540 /**
1541 * GtkWidget:hexpand: (attributes org.gtk.Property.get=gtk_widget_get_hexpand org.gtk.Property.set=gtk_widget_set_hexpand)
1542 *
1543 * Whether to expand horizontally.
1544 */
1545 widget_props[PROP_HEXPAND] =
1546 g_param_spec_boolean (name: "hexpand",
1547 P_("Horizontal Expand"),
1548 P_("Whether widget wants more horizontal space"),
1549 FALSE,
1550 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1551
1552 /**
1553 * GtkWidget:hexpand-set: (attributes org.gtk.Property.get=gtk_widget_get_hexpand_set org.gtk.Property.set=gtk_widget_set_hexpand_set)
1554 *
1555 * Whether to use the `hexpand` property.
1556 */
1557 widget_props[PROP_HEXPAND_SET] =
1558 g_param_spec_boolean (name: "hexpand-set",
1559 P_("Horizontal Expand Set"),
1560 P_("Whether to use the hexpand property"),
1561 FALSE,
1562 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1563
1564 /**
1565 * GtkWidget:vexpand: (attributes org.gtk.Property.get=gtk_widget_get_vexpand org.gtk.Property.set=gtk_widget_set_vexpand)
1566 *
1567 * Whether to expand vertically.
1568 */
1569 widget_props[PROP_VEXPAND] =
1570 g_param_spec_boolean (name: "vexpand",
1571 P_("Vertical Expand"),
1572 P_("Whether widget wants more vertical space"),
1573 FALSE,
1574 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1575
1576 /**
1577 * GtkWidget:vexpand-set: (attributes org.gtk.Property.get=gtk_widget_get_vexpand_set org.gtk.Property.set=gtk_widget_set_vexpand_set)
1578 *
1579 * Whether to use the `vexpand` property.
1580 */
1581 widget_props[PROP_VEXPAND_SET] =
1582 g_param_spec_boolean (name: "vexpand-set",
1583 P_("Vertical Expand Set"),
1584 P_("Whether to use the vexpand property"),
1585 FALSE,
1586 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1587
1588 /**
1589 * GtkWidget:opacity: (attributes org.gtk.Property.get=gtk_widget_get_opacity org.gtk.Widget.set=gtk_widget_set_opacity)
1590 *
1591 * The requested opacity of the widget.
1592 */
1593 widget_props[PROP_OPACITY] =
1594 g_param_spec_double (name: "opacity",
1595 P_("Opacity for Widget"),
1596 P_("The opacity of the widget, from 0 to 1"),
1597 minimum: 0.0, maximum: 1.0,
1598 default_value: 1.0,
1599 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1600
1601 /**
1602 * GtkWidget:overflow: (attributes org.gtk.Property.get=gtk_widget_get_overflow org.gtk.Property.set=gtk_widget_set_overflow)
1603 *
1604 * How content outside the widget's content area is treated.
1605 *
1606 * This property is meant to be set by widget implementations,
1607 * typically in their instance init function.
1608 */
1609 widget_props[PROP_OVERFLOW] =
1610 g_param_spec_enum (name: "overflow",
1611 P_("Overflow"),
1612 P_("How content outside the widget’s content area is treated"),
1613 enum_type: GTK_TYPE_OVERFLOW,
1614 default_value: GTK_OVERFLOW_VISIBLE,
1615 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1616
1617 /**
1618 * GtkWidget:scale-factor: (attributes org.gtk.Property.get=gtk_widget_get_scale_factor)
1619 *
1620 * The scale factor of the widget.
1621 */
1622 widget_props[PROP_SCALE_FACTOR] =
1623 g_param_spec_int (name: "scale-factor",
1624 P_("Scale factor"),
1625 P_("The scaling factor of the window"),
1626 minimum: 1, G_MAXINT,
1627 default_value: 1,
1628 GTK_PARAM_READABLE);
1629
1630 /**
1631 * GtkWidget:css-name: (attributes org.gtk.Property.get=gtk_widget_get_css_name)
1632 *
1633 * The name of this widget in the CSS tree.
1634 *
1635 * This property is meant to be set by widget implementations,
1636 * typically in their instance init function.
1637 */
1638 widget_props[PROP_CSS_NAME] =
1639 g_param_spec_string (name: "css-name",
1640 P_("CSS Name"),
1641 P_("The name of this widget in the CSS tree"),
1642 NULL,
1643 GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
1644
1645 /**
1646 * GtkWidget:css-classes: (attributes org.gtk.Property.get=gtk_widget_get_css_classes org.gtk.Property.set=gtk_widget_set_css_classes)
1647 *
1648 * A list of css classes applied to this widget.
1649 */
1650 widget_props[PROP_CSS_CLASSES] =
1651 g_param_spec_boxed (name: "css-classes",
1652 P_("CSS Style Classes"),
1653 P_("List of CSS classes"),
1654 G_TYPE_STRV,
1655 GTK_PARAM_READWRITE);
1656
1657 /**
1658 * GtkWidget:layout-manager: (attributes org.gtk.Property.get=gtk_widget_get_layout_manager org.gtk.Property.set=gtk_widget_set_layout_manager)
1659 *
1660 * The `GtkLayoutManager` instance to use to compute the preferred size
1661 * of the widget, and allocate its children.
1662 *
1663 * This property is meant to be set by widget implementations,
1664 * typically in their instance init function.
1665 */
1666 widget_props[PROP_LAYOUT_MANAGER] =
1667 g_param_spec_object (name: "layout-manager",
1668 P_("Layout Manager"),
1669 P_("The layout manager used to layout children of the widget"),
1670 GTK_TYPE_LAYOUT_MANAGER,
1671 GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
1672
1673 g_object_class_install_properties (oclass: gobject_class, n_pspecs: NUM_PROPERTIES, pspecs: widget_props);
1674
1675 g_object_class_override_property (oclass: gobject_class, property_id: PROP_ACCESSIBLE_ROLE, name: "accessible-role");
1676
1677 /**
1678 * GtkWidget::destroy:
1679 * @object: the object which received the signal
1680 *
1681 * Signals that all holders of a reference to the widget should release
1682 * the reference that they hold.
1683 *
1684 * May result in finalization of the widget if all references are released.
1685 *
1686 * This signal is not suitable for saving widget state.
1687 */
1688 widget_signals[DESTROY] =
1689 g_signal_new (I_("destroy"),
1690 G_TYPE_FROM_CLASS (gobject_class),
1691 signal_flags: G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
1692 class_offset: 0,
1693 NULL, NULL,
1694 NULL,
1695 G_TYPE_NONE, n_params: 0);
1696
1697 /**
1698 * GtkWidget::show:
1699 * @widget: the object which received the signal.
1700 *
1701 * Emitted when @widget is shown.
1702 */
1703 widget_signals[SHOW] =
1704 g_signal_new (I_("show"),
1705 G_TYPE_FROM_CLASS (gobject_class),
1706 signal_flags: G_SIGNAL_RUN_FIRST,
1707 G_STRUCT_OFFSET (GtkWidgetClass, show),
1708 NULL, NULL,
1709 NULL,
1710 G_TYPE_NONE, n_params: 0);
1711
1712 /**
1713 * GtkWidget::hide:
1714 * @widget: the object which received the signal.
1715 *
1716 * Emitted when @widget is hidden.
1717 */
1718 widget_signals[HIDE] =
1719 g_signal_new (I_("hide"),
1720 G_TYPE_FROM_CLASS (gobject_class),
1721 signal_flags: G_SIGNAL_RUN_FIRST,
1722 G_STRUCT_OFFSET (GtkWidgetClass, hide),
1723 NULL, NULL,
1724 NULL,
1725 G_TYPE_NONE, n_params: 0);
1726
1727 /**
1728 * GtkWidget::map:
1729 * @widget: the object which received the signal.
1730 *
1731 * Emitted when @widget is going to be mapped.
1732 *
1733 * A widget is mapped when the widget is visible (which is controlled with
1734 * [property@Gtk.Widget:visible]) and all its parents up to the toplevel widget
1735 * are also visible.
1736 *
1737 * The ::map signal can be used to determine whether a widget will be drawn,
1738 * for instance it can resume an animation that was stopped during the
1739 * emission of [signal@Gtk.Widget::unmap].
1740 */
1741 widget_signals[MAP] =
1742 g_signal_new (I_("map"),
1743 G_TYPE_FROM_CLASS (gobject_class),
1744 signal_flags: G_SIGNAL_RUN_FIRST,
1745 G_STRUCT_OFFSET (GtkWidgetClass, map),
1746 NULL, NULL,
1747 NULL,
1748 G_TYPE_NONE, n_params: 0);
1749
1750 /**
1751 * GtkWidget::unmap:
1752 * @widget: the object which received the signal.
1753 *
1754 * Emitted when @widget is going to be unmapped.
1755 *
1756 * A widget is unmapped when either it or any of its parents up to the
1757 * toplevel widget have been set as hidden.
1758 *
1759 * As ::unmap indicates that a widget will not be shown any longer,
1760 * it can be used to, for example, stop an animation on the widget.
1761 */
1762 widget_signals[UNMAP] =
1763 g_signal_new (I_("unmap"),
1764 G_TYPE_FROM_CLASS (gobject_class),
1765 signal_flags: G_SIGNAL_RUN_FIRST,
1766 G_STRUCT_OFFSET (GtkWidgetClass, unmap),
1767 NULL, NULL,
1768 NULL,
1769 G_TYPE_NONE, n_params: 0);
1770
1771 /**
1772 * GtkWidget::realize:
1773 * @widget: the object which received the signal.
1774 *
1775 * Emitted when @widget is associated with a `GdkSurface`.
1776 *
1777 * This means that [method@Gtk.Widget.realize] has been called
1778 * or the widget has been mapped (that is, it is going to be drawn).
1779 */
1780 widget_signals[REALIZE] =
1781 g_signal_new (I_("realize"),
1782 G_TYPE_FROM_CLASS (gobject_class),
1783 signal_flags: G_SIGNAL_RUN_FIRST,
1784 G_STRUCT_OFFSET (GtkWidgetClass, realize),
1785 NULL, NULL,
1786 NULL,
1787 G_TYPE_NONE, n_params: 0);
1788
1789 /**
1790 * GtkWidget::unrealize:
1791 * @widget: the object which received the signal.
1792 *
1793 * Emitted when the `GdkSurface` associated with @widget is destroyed.
1794 *
1795 * This means that [method@Gtk.Widget.unrealize] has been called
1796 * or the widget has been unmapped (that is, it is going to be hidden).
1797 */
1798 widget_signals[UNREALIZE] =
1799 g_signal_new (I_("unrealize"),
1800 G_TYPE_FROM_CLASS (gobject_class),
1801 signal_flags: G_SIGNAL_RUN_LAST,
1802 G_STRUCT_OFFSET (GtkWidgetClass, unrealize),
1803 NULL, NULL,
1804 NULL,
1805 G_TYPE_NONE, n_params: 0);
1806
1807 /**
1808 * GtkWidget::state-flags-changed:
1809 * @widget: the object which received the signal.
1810 * @flags: The previous state flags.
1811 *
1812 * Emitted when the widget state changes.
1813 *
1814 * See [method@Gtk.Widget.get_state_flags].
1815 */
1816 widget_signals[STATE_FLAGS_CHANGED] =
1817 g_signal_new (I_("state-flags-changed"),
1818 G_TYPE_FROM_CLASS (gobject_class),
1819 signal_flags: G_SIGNAL_RUN_FIRST,
1820 G_STRUCT_OFFSET (GtkWidgetClass, state_flags_changed),
1821 NULL, NULL,
1822 NULL,
1823 G_TYPE_NONE, n_params: 1,
1824 GTK_TYPE_STATE_FLAGS);
1825
1826 /**
1827 * GtkWidget::direction-changed:
1828 * @widget: the object on which the signal is emitted
1829 * @previous_direction: the previous text direction of @widget
1830 *
1831 * Emitted when the text direction of a widget changes.
1832 */
1833 widget_signals[DIRECTION_CHANGED] =
1834 g_signal_new (I_("direction-changed"),
1835 G_TYPE_FROM_CLASS (gobject_class),
1836 signal_flags: G_SIGNAL_RUN_FIRST,
1837 G_STRUCT_OFFSET (GtkWidgetClass, direction_changed),
1838 NULL, NULL,
1839 NULL,
1840 G_TYPE_NONE, n_params: 1,
1841 GTK_TYPE_TEXT_DIRECTION);
1842
1843 /**
1844 * GtkWidget::mnemonic-activate:
1845 * @widget: the object which received the signal.
1846 * @group_cycling: %TRUE if there are other widgets with the same mnemonic
1847 *
1848 * Emitted when a widget is activated via a mnemonic.
1849 *
1850 * The default handler for this signal activates @widget if @group_cycling
1851 * is %FALSE, or just makes @widget grab focus if @group_cycling is %TRUE.
1852 *
1853 * Returns: %TRUE to stop other handlers from being invoked for the event.
1854 * %FALSE to propagate the event further.
1855 */
1856 widget_signals[MNEMONIC_ACTIVATE] =
1857 g_signal_new (I_("mnemonic-activate"),
1858 G_TYPE_FROM_CLASS (gobject_class),
1859 signal_flags: G_SIGNAL_RUN_LAST,
1860 G_STRUCT_OFFSET (GtkWidgetClass, mnemonic_activate),
1861 accumulator: _gtk_boolean_handled_accumulator, NULL,
1862 c_marshaller: _gtk_marshal_BOOLEAN__BOOLEAN,
1863 G_TYPE_BOOLEAN, n_params: 1,
1864 G_TYPE_BOOLEAN);
1865 g_signal_set_va_marshaller (signal_id: widget_signals[MNEMONIC_ACTIVATE],
1866 G_TYPE_FROM_CLASS (gobject_class),
1867 va_marshaller: _gtk_marshal_BOOLEAN__BOOLEANv);
1868
1869 /**
1870 * GtkWidget::move-focus:
1871 * @widget: the object which received the signal.
1872 * @direction: the direction of the focus move
1873 *
1874 * Emitted when the focus is moved.
1875 */
1876 widget_signals[MOVE_FOCUS] =
1877 g_signal_new (I_("move-focus"),
1878 G_TYPE_FROM_CLASS (klass),
1879 signal_flags: G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1880 G_STRUCT_OFFSET (GtkWidgetClass, move_focus),
1881 NULL, NULL,
1882 NULL,
1883 G_TYPE_NONE,
1884 n_params: 1,
1885 GTK_TYPE_DIRECTION_TYPE);
1886
1887 /**
1888 * GtkWidget::keynav-failed:
1889 * @widget: the object which received the signal
1890 * @direction: the direction of movement
1891 *
1892 * Emitted if keyboard navigation fails.
1893 *
1894 * See [method@Gtk.Widget.keynav_failed] for details.
1895 *
1896 * Returns: %TRUE if stopping keyboard navigation is fine, %FALSE
1897 * if the emitting widget should try to handle the keyboard
1898 * navigation attempt in its parent widget(s).
1899 */
1900 widget_signals[KEYNAV_FAILED] =
1901 g_signal_new (I_("keynav-failed"),
1902 G_TYPE_FROM_CLASS (klass),
1903 signal_flags: G_SIGNAL_RUN_LAST,
1904 G_STRUCT_OFFSET (GtkWidgetClass, keynav_failed),
1905 accumulator: _gtk_boolean_handled_accumulator, NULL,
1906 c_marshaller: _gtk_marshal_BOOLEAN__ENUM,
1907 G_TYPE_BOOLEAN, n_params: 1,
1908 GTK_TYPE_DIRECTION_TYPE);
1909 g_signal_set_va_marshaller (signal_id: widget_signals[KEYNAV_FAILED],
1910 G_TYPE_FROM_CLASS (klass),
1911 va_marshaller: _gtk_marshal_BOOLEAN__ENUMv);
1912
1913 /**
1914 * GtkWidget::query-tooltip:
1915 * @widget: the object which received the signal
1916 * @x: the x coordinate of the cursor position where the request has
1917 * been emitted, relative to @widget's left side
1918 * @y: the y coordinate of the cursor position where the request has
1919 * been emitted, relative to @widget's top
1920 * @keyboard_mode: %TRUE if the tooltip was triggered using the keyboard
1921 * @tooltip: a `GtkTooltip`
1922 *
1923 * Emitted when the widgets tooltip is about to be shown.
1924 *
1925 * This happens when the [property@Gtk.Widget:has-tooltip] property
1926 * is %TRUE and the hover timeout has expired with the cursor hovering
1927 * "above" @widget; or emitted when @widget got focus in keyboard mode.
1928 *
1929 * Using the given coordinates, the signal handler should determine
1930 * whether a tooltip should be shown for @widget. If this is the case
1931 * %TRUE should be returned, %FALSE otherwise. Note that if
1932 * @keyboard_mode is %TRUE, the values of @x and @y are undefined and
1933 * should not be used.
1934 *
1935 * The signal handler is free to manipulate @tooltip with the therefore
1936 * destined function calls.
1937 *
1938 * Returns: %TRUE if @tooltip should be shown right now, %FALSE otherwise.
1939 */
1940 widget_signals[QUERY_TOOLTIP] =
1941 g_signal_new (I_("query-tooltip"),
1942 G_TYPE_FROM_CLASS (klass),
1943 signal_flags: G_SIGNAL_RUN_LAST,
1944 G_STRUCT_OFFSET (GtkWidgetClass, query_tooltip),
1945 accumulator: _gtk_boolean_handled_accumulator, NULL,
1946 c_marshaller: _gtk_marshal_BOOLEAN__INT_INT_BOOLEAN_OBJECT,
1947 G_TYPE_BOOLEAN, n_params: 4,
1948 G_TYPE_INT,
1949 G_TYPE_INT,
1950 G_TYPE_BOOLEAN,
1951 GTK_TYPE_TOOLTIP);
1952 g_signal_set_va_marshaller (signal_id: widget_signals[QUERY_TOOLTIP],
1953 G_TYPE_FROM_CLASS (klass),
1954 va_marshaller: _gtk_marshal_BOOLEAN__INT_INT_BOOLEAN_OBJECTv);
1955
1956 gtk_widget_class_set_css_name (widget_class: klass, I_("widget"));
1957 gtk_widget_class_set_accessible_role (widget_class: klass, accessible_role: GTK_ACCESSIBLE_ROLE_WIDGET);
1958}
1959
1960static void
1961template_child_class_free (AutomaticChildClass *child_class)
1962{
1963 if (child_class)
1964 {
1965 g_free (mem: child_class->name);
1966 g_slice_free (AutomaticChildClass, child_class);
1967 }
1968}
1969
1970static void
1971gtk_widget_base_class_finalize (GtkWidgetClass *klass)
1972{
1973 GtkWidgetTemplate *template_data = klass->priv->template;
1974
1975 if (template_data)
1976 {
1977 g_bytes_unref (bytes: template_data->data);
1978 g_slist_free_full (list: template_data->children, free_func: (GDestroyNotify)template_child_class_free);
1979
1980 g_object_unref (object: template_data->scope);
1981
1982 g_slice_free (GtkWidgetTemplate, template_data);
1983 }
1984
1985 g_object_unref (object: klass->priv->shortcuts);
1986}
1987
1988static void
1989_gtk_widget_emulate_press (GtkWidget *widget,
1990 GdkEvent *event,
1991 GtkWidget *event_widget)
1992{
1993 GtkWidget *next_child, *parent;
1994 GdkEvent *press;
1995 double x, y;
1996 graphene_point_t p;
1997
1998 if (event_widget == widget)
1999 return;
2000
2001 switch ((guint) gdk_event_get_event_type (event))
2002 {
2003 case GDK_TOUCH_BEGIN:
2004 case GDK_TOUCH_UPDATE:
2005 case GDK_TOUCH_END:
2006 case GDK_BUTTON_PRESS:
2007 case GDK_BUTTON_RELEASE:
2008 case GDK_MOTION_NOTIFY:
2009 gdk_event_get_position (event, x: &x, y: &y);
2010 if (!gtk_widget_compute_point (widget: event_widget,
2011 GTK_WIDGET (gtk_widget_get_root (event_widget)),
2012 point: &GRAPHENE_POINT_INIT (x, y),
2013 out_point: &p))
2014 return;
2015 break;
2016 default:
2017 return;
2018 }
2019
2020 switch ((guint) gdk_event_get_event_type (event))
2021 {
2022 case GDK_TOUCH_BEGIN:
2023 case GDK_TOUCH_UPDATE:
2024 case GDK_TOUCH_END:
2025 press = gdk_touch_event_new (type: GDK_TOUCH_BEGIN,
2026 sequence: gdk_event_get_event_sequence (event),
2027 surface: gdk_event_get_surface (event),
2028 device: gdk_event_get_device (event),
2029 time: gdk_event_get_time (event),
2030 state: gdk_event_get_modifier_state (event),
2031 x: p.x, y: p.y,
2032 NULL,
2033 emulating: gdk_touch_event_get_emulating_pointer (event));
2034 break;
2035 case GDK_BUTTON_PRESS:
2036 case GDK_BUTTON_RELEASE:
2037 press = gdk_button_event_new (type: GDK_BUTTON_PRESS,
2038 surface: gdk_event_get_surface (event),
2039 device: gdk_event_get_device (event),
2040 tool: gdk_event_get_device_tool (event),
2041 time: gdk_event_get_time (event),
2042 state: gdk_event_get_modifier_state (event),
2043 button: gdk_button_event_get_button (event),
2044 x: p.x, y: p.y,
2045 NULL);
2046 break;
2047 case GDK_MOTION_NOTIFY:
2048 {
2049 GdkModifierType state = gdk_event_get_modifier_state (event);
2050 int button;
2051 if (state & GDK_BUTTON3_MASK)
2052 button = 3;
2053 else if (state & GDK_BUTTON2_MASK)
2054 button = 2;
2055 else
2056 {
2057 if ((state & GDK_BUTTON1_MASK) == 0)
2058 g_critical ("Guessing button number 1 on generated button press event");
2059 button = 1;
2060 }
2061
2062 press = gdk_button_event_new (type: GDK_BUTTON_PRESS,
2063 surface: gdk_event_get_surface (event),
2064 device: gdk_event_get_device (event),
2065 tool: gdk_event_get_device_tool (event),
2066 time: gdk_event_get_time (event),
2067 state: gdk_event_get_modifier_state (event),
2068 button,
2069 x: p.x, y: p.y,
2070 NULL);
2071 }
2072 break;
2073 default:
2074 g_assert_not_reached ();
2075 }
2076
2077 next_child = event_widget;
2078 parent = _gtk_widget_get_parent (widget: next_child);
2079
2080 while (parent && parent != widget)
2081 {
2082 next_child = parent;
2083 parent = _gtk_widget_get_parent (widget: parent);
2084 }
2085
2086 /* Perform propagation state starting from the next child in the chain */
2087 gtk_propagate_event_internal (widget: event_widget, event: press, topmost: next_child);
2088 gdk_event_unref (event: press);
2089}
2090
2091static GdkEvent *
2092_gtk_widget_get_last_event (GtkWidget *widget,
2093 GdkEventSequence *sequence,
2094 GtkWidget **target)
2095{
2096 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
2097 GtkEventController *controller;
2098 GdkEvent *event;
2099 GList *l;
2100
2101 for (l = priv->event_controllers; l; l = l->next)
2102 {
2103 controller = l->data;
2104
2105 if (!GTK_IS_GESTURE (controller))
2106 continue;
2107
2108 event = gtk_gesture_get_last_event (GTK_GESTURE (controller), sequence);
2109 if (event)
2110 {
2111 *target = gtk_gesture_get_last_target (GTK_GESTURE (controller), sequence);
2112 return event;
2113 }
2114 }
2115
2116 *target = NULL;
2117 return NULL;
2118}
2119
2120static gboolean
2121_gtk_widget_get_emulating_sequence (GtkWidget *widget,
2122 GdkEventSequence *sequence,
2123 GdkEventSequence **sequence_out)
2124{
2125 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
2126
2127 *sequence_out = sequence;
2128
2129 if (sequence)
2130 {
2131 GdkEvent *last_event;
2132 GtkWidget *target;
2133
2134 last_event = _gtk_widget_get_last_event (widget, sequence, target: &target);
2135
2136 if (last_event &&
2137 (gdk_event_get_event_type (event: last_event) == GDK_TOUCH_BEGIN ||
2138 gdk_event_get_event_type (event: last_event) == GDK_TOUCH_UPDATE ||
2139 gdk_event_get_event_type (event: last_event) == GDK_TOUCH_END) &&
2140 gdk_touch_event_get_emulating_pointer (event: last_event))
2141 return TRUE;
2142 }
2143 else
2144 {
2145 GList *l;
2146
2147 /* For a NULL(pointer) sequence, find the pointer emulating one */
2148 for (l = priv->event_controllers; l; l = l->next)
2149 {
2150 GtkEventController *controller = l->data;
2151
2152 if (!GTK_IS_GESTURE (controller))
2153 continue;
2154
2155 if (_gtk_gesture_get_pointer_emulating_sequence (GTK_GESTURE (controller),
2156 sequence: sequence_out))
2157 return TRUE;
2158 }
2159 }
2160
2161 return FALSE;
2162}
2163
2164static gboolean
2165gtk_widget_needs_press_emulation (GtkWidget *widget,
2166 GdkEventSequence *sequence)
2167{
2168 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
2169 gboolean sequence_press_handled = FALSE;
2170 GList *l;
2171
2172 /* Check whether there is any remaining gesture in
2173 * the capture phase that handled the press event
2174 */
2175 for (l = priv->event_controllers; l; l = l->next)
2176 {
2177 GtkEventController *controller = l->data;
2178 GtkPropagationPhase phase;
2179 GtkGesture *gesture;
2180
2181 phase = gtk_event_controller_get_propagation_phase (controller);
2182
2183 if (phase != GTK_PHASE_CAPTURE)
2184 continue;
2185 if (!GTK_IS_GESTURE (controller))
2186 continue;
2187
2188 gesture = GTK_GESTURE (controller);
2189 sequence_press_handled |=
2190 (gtk_gesture_handles_sequence (gesture, sequence) &&
2191 _gtk_gesture_handled_sequence_press (gesture, sequence));
2192 }
2193
2194 return !sequence_press_handled;
2195}
2196
2197static int
2198_gtk_widget_set_sequence_state_internal (GtkWidget *widget,
2199 GdkEventSequence *sequence,
2200 GtkEventSequenceState state,
2201 GtkGesture *emitter)
2202{
2203 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
2204 gboolean emulates_pointer, sequence_handled = FALSE;
2205 GdkEvent *mimic_event;
2206 GtkWidget *target;
2207 GList *group = NULL, *l;
2208 GdkEventSequence *seq;
2209 int n_handled = 0;
2210
2211 if (!priv->event_controllers && state != GTK_EVENT_SEQUENCE_CLAIMED)
2212 return TRUE;
2213
2214 if (emitter)
2215 group = gtk_gesture_get_group (gesture: emitter);
2216
2217 emulates_pointer = _gtk_widget_get_emulating_sequence (widget, sequence, sequence_out: &seq);
2218 mimic_event = _gtk_widget_get_last_event (widget, sequence: seq, target: &target);
2219
2220 for (l = priv->event_controllers; l; l = l->next)
2221 {
2222 GtkEventController *controller;
2223 GtkEventSequenceState gesture_state;
2224 GtkGesture *gesture;
2225 gboolean retval;
2226
2227 seq = sequence;
2228 controller = l->data;
2229 gesture_state = state;
2230
2231 if (!GTK_IS_GESTURE (controller))
2232 continue;
2233
2234 gesture = GTK_GESTURE (controller);
2235
2236 if (gesture == emitter)
2237 {
2238 sequence_handled |=
2239 _gtk_gesture_handled_sequence_press (gesture, sequence);
2240 n_handled++;
2241 continue;
2242 }
2243
2244 if (seq && emulates_pointer &&
2245 !gtk_gesture_handles_sequence (gesture, sequence: seq))
2246 seq = NULL;
2247
2248 if (group && !g_list_find (list: group, data: controller))
2249 {
2250 /* If a group is provided, ensure only gestures pertaining to the group
2251 * get a "claimed" state, all other claiming gestures must deny the sequence.
2252 */
2253 if (state == GTK_EVENT_SEQUENCE_CLAIMED)
2254 gesture_state = GTK_EVENT_SEQUENCE_DENIED;
2255 else
2256 continue;
2257 }
2258 else if (!group &&
2259 gtk_gesture_get_sequence_state (gesture, sequence) != GTK_EVENT_SEQUENCE_CLAIMED)
2260 continue;
2261
2262 retval = gtk_gesture_set_sequence_state (gesture, sequence: seq, state: gesture_state);
2263
2264 if (retval || gesture == emitter)
2265 {
2266 sequence_handled |=
2267 _gtk_gesture_handled_sequence_press (gesture, sequence: seq);
2268 n_handled++;
2269 }
2270 }
2271
2272 /* If the sequence goes denied, check whether this is a controller attached
2273 * to the capture phase, that additionally handled the button/touch press (i.e.
2274 * it was consumed), the corresponding press will be emulated for widgets
2275 * beneath, so the widgets beneath get a coherent stream of events from now on.
2276 */
2277 if (n_handled > 0 && sequence_handled &&
2278 state == GTK_EVENT_SEQUENCE_DENIED &&
2279 gtk_widget_needs_press_emulation (widget, sequence))
2280 _gtk_widget_emulate_press (widget, event: mimic_event, event_widget: target);
2281
2282 g_list_free (list: group);
2283
2284 return n_handled;
2285}
2286
2287static gboolean
2288_gtk_widget_cancel_sequence (GtkWidget *widget,
2289 GdkEventSequence *sequence)
2290{
2291 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
2292 gboolean handled = FALSE;
2293 GList *l;
2294
2295 for (l = priv->event_controllers; l; l = l->next)
2296 {
2297 GtkEventController *controller;
2298 GtkGesture *gesture;
2299
2300 controller = l->data;
2301
2302 if (!GTK_IS_GESTURE (controller))
2303 continue;
2304
2305 gesture = GTK_GESTURE (controller);
2306
2307 handled |= _gtk_gesture_cancel_sequence (gesture, sequence);
2308 }
2309
2310 return handled;
2311}
2312
2313static gboolean
2314gtk_widget_class_get_visible_by_default (GtkWidgetClass *widget_class)
2315{
2316 return !g_type_is_a (G_TYPE_FROM_CLASS (widget_class), GTK_TYPE_NATIVE);
2317}
2318
2319static void
2320gtk_widget_init (GTypeInstance *instance, gpointer g_class)
2321{
2322 GtkWidget *widget = GTK_WIDGET (instance);
2323 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
2324 GType layout_manager_type;
2325 GtkEventController *controller;
2326
2327 widget->priv = priv;
2328
2329 priv->visible = gtk_widget_class_get_visible_by_default (widget_class: g_class);
2330 priv->child_visible = TRUE;
2331 priv->name = NULL;
2332 priv->user_alpha = 255;
2333 priv->parent = NULL;
2334 priv->first_child = NULL;
2335 priv->last_child = NULL;
2336 priv->prev_sibling = NULL;
2337 priv->next_sibling = NULL;
2338 priv->baseline = -1;
2339 priv->allocated_size_baseline = -1;
2340
2341 priv->sensitive = TRUE;
2342 priv->alloc_needed = TRUE;
2343 priv->alloc_needed_on_child = TRUE;
2344 priv->draw_needed = TRUE;
2345 priv->focus_on_click = TRUE;
2346 priv->can_focus = TRUE;
2347 priv->focusable = FALSE;
2348 priv->can_target = TRUE;
2349
2350 switch (_gtk_widget_get_direction (widget))
2351 {
2352 case GTK_TEXT_DIR_LTR:
2353 priv->state_flags = GTK_STATE_FLAG_DIR_LTR;
2354 break;
2355
2356 case GTK_TEXT_DIR_RTL:
2357 priv->state_flags = GTK_STATE_FLAG_DIR_RTL;
2358 break;
2359
2360 case GTK_TEXT_DIR_NONE:
2361 default:
2362 g_assert_not_reached ();
2363 break;
2364 }
2365
2366 /* this will be set to TRUE if the widget gets a child or if the
2367 * expand flag is set on the widget, but until one of those happen
2368 * we know the expand is already properly FALSE.
2369 *
2370 * We really want to default FALSE here to avoid computing expand
2371 * all over the place while initially building a widget tree.
2372 */
2373 priv->need_compute_expand = FALSE;
2374
2375 priv->halign = GTK_ALIGN_FILL;
2376 priv->valign = GTK_ALIGN_FILL;
2377
2378 priv->accessible_role = GTK_ACCESSIBLE_ROLE_WIDGET;
2379
2380 priv->width_request = -1;
2381 priv->height_request = -1;
2382
2383 _gtk_size_request_cache_init (cache: &priv->requests);
2384
2385 priv->cssnode = gtk_css_widget_node_new (widget);
2386 gtk_css_node_set_state (cssnode: priv->cssnode, state_flags: priv->state_flags);
2387 gtk_css_node_set_visible (cssnode: priv->cssnode, visible: priv->visible);
2388 /* need to set correct name here, and only class has the correct type here */
2389 gtk_css_node_set_name (cssnode: priv->cssnode, GTK_WIDGET_CLASS (g_class)->priv->css_name);
2390
2391 if (g_type_is_a (G_TYPE_FROM_CLASS (g_class), GTK_TYPE_ROOT))
2392 priv->root = (GtkRoot *) widget;
2393
2394 if (g_type_is_a (G_TYPE_FROM_CLASS (g_class), GTK_TYPE_SHORTCUT_MANAGER))
2395 gtk_shortcut_manager_create_controllers (widget);
2396
2397 layout_manager_type = gtk_widget_class_get_layout_manager_type (widget_class: g_class);
2398 if (layout_manager_type != G_TYPE_INVALID)
2399 gtk_widget_set_layout_manager (widget, layout_manager: g_object_new (object_type: layout_manager_type, NULL));
2400
2401 if (g_list_model_get_n_items (list: G_LIST_MODEL (GTK_WIDGET_CLASS (g_class)->priv->shortcuts)) > 0)
2402 {
2403 controller = gtk_shortcut_controller_new_for_model (model: G_LIST_MODEL (GTK_WIDGET_CLASS (g_class)->priv->shortcuts));
2404 gtk_event_controller_set_name (controller, name: "gtk-widget-class-shortcuts");
2405 gtk_widget_add_controller (widget, controller);
2406 }
2407
2408 priv->at_context = gtk_accessible_get_at_context (self: GTK_ACCESSIBLE (ptr: widget));
2409}
2410
2411static void
2412gtk_widget_root_at_context (GtkWidget *self)
2413{
2414 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self);
2415 GtkAccessibleRole role = priv->accessible_role;
2416
2417 if (priv->at_context == NULL)
2418 return;
2419
2420 /* Reset the accessible role to its current value */
2421 if (role == GTK_ACCESSIBLE_ROLE_WIDGET)
2422 {
2423 GtkWidgetClassPrivate *class_priv = GTK_WIDGET_GET_CLASS (self)->priv;
2424
2425 role = class_priv->accessible_role;
2426 }
2427
2428 gtk_at_context_set_accessible_role (self: priv->at_context, role);
2429 gtk_at_context_set_display (self: priv->at_context, display: gtk_root_get_display (self: priv->root));
2430}
2431
2432static void
2433gtk_widget_unroot_at_context (GtkWidget *self)
2434{
2435 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self);
2436
2437 if (priv->at_context != NULL)
2438 {
2439 gtk_at_context_set_display (self: priv->at_context, display: gdk_display_get_default ());
2440 gtk_at_context_unrealize (self: priv->at_context);
2441 }
2442}
2443
2444void
2445gtk_widget_realize_at_context (GtkWidget *self)
2446{
2447 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self);
2448
2449 if (priv->at_context == NULL || gtk_at_context_is_realized (self: priv->at_context))
2450 return;
2451
2452 gtk_widget_root_at_context (self);
2453 gtk_at_context_realize (self: priv->at_context);
2454}
2455
2456void
2457gtk_widget_unrealize_at_context (GtkWidget *widget)
2458{
2459 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
2460
2461 if (priv->at_context != NULL)
2462 {
2463 gtk_at_context_set_display (self: priv->at_context, display: gdk_display_get_default ());
2464 gtk_at_context_unrealize (self: priv->at_context);
2465 }
2466}
2467
2468void
2469gtk_widget_root (GtkWidget *widget)
2470{
2471 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
2472
2473 g_assert (!priv->realized);
2474
2475 if (GTK_IS_ROOT (ptr: widget))
2476 {
2477 g_assert (priv->root == GTK_ROOT (widget));
2478 }
2479 else
2480 {
2481 g_assert (priv->root == NULL);
2482 priv->root = priv->parent->priv->root;
2483 }
2484
2485 if (priv->context)
2486 gtk_style_context_set_display (context: priv->context, display: gtk_root_get_display (self: priv->root));
2487
2488 if (priv->surface_transform_data)
2489 add_parent_surface_transform_changed_listener (widget);
2490
2491 _gtk_widget_update_parent_muxer (widget);
2492
2493 if (priv->layout_manager)
2494 gtk_layout_manager_set_root (manager: priv->layout_manager, root: priv->root);
2495
2496 gtk_widget_root_at_context (self: widget);
2497
2498 GTK_WIDGET_GET_CLASS (widget)->root (widget);
2499
2500 if (!GTK_IS_ROOT (ptr: widget))
2501 g_object_notify_by_pspec (G_OBJECT (widget), pspec: widget_props[PROP_ROOT]);
2502}
2503
2504void
2505gtk_widget_unroot (GtkWidget *widget)
2506{
2507 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
2508 GtkWidgetSurfaceTransformData *surface_transform_data;
2509
2510 g_assert (priv->root);
2511 g_assert (!priv->realized);
2512
2513 surface_transform_data = priv->surface_transform_data;
2514 if (surface_transform_data &&
2515 surface_transform_data->tracked_parent)
2516 remove_parent_surface_transform_changed_listener (widget);
2517
2518 _gtk_widget_update_parent_muxer (widget);
2519
2520 GTK_WIDGET_GET_CLASS (widget)->unroot (widget);
2521
2522 if (priv->context)
2523 gtk_style_context_set_display (context: priv->context, display: gdk_display_get_default ());
2524
2525 if (priv->layout_manager)
2526 gtk_layout_manager_set_root (manager: priv->layout_manager, NULL);
2527
2528 if (g_object_get_qdata (G_OBJECT (widget), quark: quark_pango_context))
2529 g_object_set_qdata (G_OBJECT (widget), quark: quark_pango_context, NULL);
2530
2531 _gtk_tooltip_hide (widget);
2532
2533 if (!GTK_IS_ROOT (ptr: widget))
2534 {
2535 /* Roots unrealize the ATContext on unmap */
2536 gtk_widget_unroot_at_context (self: widget);
2537
2538 priv->root = NULL;
2539 g_object_notify_by_pspec (G_OBJECT (widget), pspec: widget_props[PROP_ROOT]);
2540 }
2541}
2542
2543/**
2544 * gtk_widget_unparent:
2545 * @widget: a `GtkWidget`
2546 *
2547 * Dissociate @widget from its parent.
2548 *
2549 * This function is only for use in widget implementations,
2550 * typically in dispose.
2551 */
2552void
2553gtk_widget_unparent (GtkWidget *widget)
2554{
2555 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
2556 GtkWidget *old_parent;
2557 GtkWidget *old_prev_sibling;
2558 GtkRoot *root;
2559
2560 g_return_if_fail (GTK_IS_WIDGET (widget));
2561
2562 if (priv->parent == NULL)
2563 return;
2564
2565 gtk_widget_push_verify_invariants (widget);
2566
2567 g_object_freeze_notify (G_OBJECT (widget));
2568
2569 gtk_accessible_update_children (self: GTK_ACCESSIBLE (ptr: priv->parent),
2570 child: GTK_ACCESSIBLE (ptr: widget),
2571 state: GTK_ACCESSIBLE_CHILD_STATE_REMOVED);
2572
2573 root = _gtk_widget_get_root (widget);
2574 if (GTK_IS_WINDOW (root))
2575 _gtk_window_unset_focus_and_default (GTK_WINDOW (root), widget);
2576
2577 if (gtk_widget_get_focus_child (widget: priv->parent) == widget)
2578 gtk_widget_set_focus_child (widget: priv->parent, NULL);
2579
2580 if (_gtk_widget_get_mapped (widget: priv->parent))
2581 gtk_widget_queue_draw (widget: priv->parent);
2582
2583 if (priv->visible && _gtk_widget_get_visible (widget: priv->parent))
2584 gtk_widget_queue_resize (widget: priv->parent);
2585
2586 /* Reset the width and height here, to force reallocation if we
2587 * get added back to a new parent.
2588 */
2589 priv->width = 0;
2590 priv->height = 0;
2591
2592 if (_gtk_widget_get_realized (widget))
2593 gtk_widget_unrealize (widget);
2594
2595 if (priv->root)
2596 gtk_widget_unroot (widget);
2597
2598 root = NULL;
2599
2600 /* Removing a widget from a container restores the child visible
2601 * flag to the default state, so it doesn't affect the child
2602 * in the next parent.
2603 */
2604 priv->child_visible = TRUE;
2605
2606 old_parent = priv->parent;
2607 if (old_parent)
2608 {
2609 if (old_parent->priv->first_child == widget)
2610 old_parent->priv->first_child = priv->next_sibling;
2611
2612 if (old_parent->priv->last_child == widget)
2613 old_parent->priv->last_child = priv->prev_sibling;
2614
2615 if (priv->prev_sibling)
2616 priv->prev_sibling->priv->next_sibling = priv->next_sibling;
2617 if (priv->next_sibling)
2618 priv->next_sibling->priv->prev_sibling = priv->prev_sibling;
2619 }
2620 old_prev_sibling = priv->prev_sibling;
2621 priv->parent = NULL;
2622 priv->prev_sibling = NULL;
2623 priv->next_sibling = NULL;
2624
2625 /* parent may no longer expand if the removed
2626 * child was expand=TRUE and could therefore
2627 * be forcing it to.
2628 */
2629 if (_gtk_widget_get_visible (widget) &&
2630 (priv->need_compute_expand ||
2631 priv->computed_hexpand ||
2632 priv->computed_vexpand))
2633 {
2634 gtk_widget_queue_compute_expand (widget: old_parent);
2635 }
2636
2637 /* Unset BACKDROP since we are no longer inside a toplevel window */
2638 gtk_widget_unset_state_flags (widget, flags: GTK_STATE_FLAG_BACKDROP);
2639 gtk_css_node_set_parent (cssnode: priv->cssnode, NULL);
2640
2641 _gtk_widget_update_parent_muxer (widget);
2642
2643 if (old_parent->priv->children_observer)
2644 gtk_list_list_model_item_removed (self: old_parent->priv->children_observer, previous: old_prev_sibling);
2645
2646 if (old_parent->priv->layout_manager)
2647 gtk_layout_manager_remove_layout_child (manager: old_parent->priv->layout_manager, widget);
2648
2649 g_object_notify_by_pspec (G_OBJECT (widget), pspec: widget_props[PROP_PARENT]);
2650 g_object_thaw_notify (G_OBJECT (widget));
2651
2652 gtk_widget_pop_verify_invariants (widget);
2653 g_object_unref (object: widget);
2654}
2655
2656static void
2657gtk_widget_update_paintables (GtkWidget *widget)
2658{
2659 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
2660 GSList *l;
2661
2662 for (l = priv->paintables; l; l = l->next)
2663 gtk_widget_paintable_update_image (self: l->data);
2664}
2665
2666static void
2667gtk_widget_push_paintables (GtkWidget *widget)
2668{
2669 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
2670 GSList *l;
2671
2672 for (l = priv->paintables; l; l = l->next)
2673 gtk_widget_paintable_push_snapshot_count (self: l->data);
2674}
2675
2676static void
2677gtk_widget_pop_paintables (GtkWidget *widget)
2678{
2679 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
2680 GSList *l;
2681
2682 for (l = priv->paintables; l; l = l->next)
2683 gtk_widget_paintable_pop_snapshot_count (self: l->data);
2684}
2685
2686/**
2687 * gtk_widget_show:
2688 * @widget: a `GtkWidget`
2689 *
2690 * Flags a widget to be displayed.
2691 *
2692 * Any widget that isn’t shown will not appear on the screen.
2693 *
2694 * Remember that you have to show the containers containing a widget,
2695 * in addition to the widget itself, before it will appear onscreen.
2696 *
2697 * When a toplevel container is shown, it is immediately realized and
2698 * mapped; other shown widgets are realized and mapped when their
2699 * toplevel container is realized and mapped.
2700 */
2701void
2702gtk_widget_show (GtkWidget *widget)
2703{
2704 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
2705
2706 g_return_if_fail (GTK_IS_WIDGET (widget));
2707
2708 if (!_gtk_widget_get_visible (widget))
2709 {
2710 GtkWidget *parent;
2711
2712 g_object_ref (widget);
2713 gtk_widget_push_verify_invariants (widget);
2714
2715 parent = _gtk_widget_get_parent (widget);
2716 if (parent)
2717 {
2718 gtk_widget_queue_resize (widget: parent);
2719
2720 /* see comment in set_parent() for why this should and can be
2721 * conditional
2722 */
2723 if (priv->need_compute_expand ||
2724 priv->computed_hexpand ||
2725 priv->computed_vexpand)
2726 gtk_widget_queue_compute_expand (widget: parent);
2727 }
2728
2729 gtk_css_node_set_visible (cssnode: priv->cssnode, TRUE);
2730
2731 g_signal_emit (instance: widget, signal_id: widget_signals[SHOW], detail: 0);
2732 g_object_notify_by_pspec (G_OBJECT (widget), pspec: widget_props[PROP_VISIBLE]);
2733
2734 gtk_accessible_update_state (self: GTK_ACCESSIBLE (ptr: widget),
2735 first_state: GTK_ACCESSIBLE_STATE_HIDDEN, FALSE,
2736 -1);
2737
2738 gtk_widget_pop_verify_invariants (widget);
2739 g_object_unref (object: widget);
2740 }
2741}
2742
2743static void
2744gtk_widget_real_show (GtkWidget *widget)
2745{
2746 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
2747
2748 g_return_if_fail (!_gtk_widget_get_visible (widget));
2749
2750 priv->visible = TRUE;
2751
2752 if (priv->parent &&
2753 _gtk_widget_get_mapped (widget: priv->parent) &&
2754 _gtk_widget_get_child_visible (widget) &&
2755 !_gtk_widget_get_mapped (widget))
2756 gtk_widget_map (widget);
2757}
2758
2759/**
2760 * gtk_widget_hide:
2761 * @widget: a `GtkWidget`
2762 *
2763 * Reverses the effects of gtk_widget_show().
2764 *
2765 * This is causing the widget to be hidden (invisible to the user).
2766 */
2767void
2768gtk_widget_hide (GtkWidget *widget)
2769{
2770 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
2771
2772 g_return_if_fail (GTK_IS_WIDGET (widget));
2773
2774 if (_gtk_widget_get_visible (widget))
2775 {
2776 GtkWidget *parent;
2777 GtkRoot *root;
2778
2779 g_object_ref (widget);
2780 gtk_widget_push_verify_invariants (widget);
2781
2782 root = _gtk_widget_get_root (widget);
2783 if (GTK_WIDGET (root) != widget && GTK_IS_WINDOW (root))
2784 _gtk_window_unset_focus_and_default (GTK_WINDOW (root), widget);
2785
2786 /* a parent may now be expand=FALSE since we're hidden. */
2787 if (priv->need_compute_expand ||
2788 priv->computed_hexpand ||
2789 priv->computed_vexpand)
2790 {
2791 gtk_widget_queue_compute_expand (widget);
2792 }
2793
2794 gtk_css_node_set_visible (cssnode: priv->cssnode, FALSE);
2795
2796 g_signal_emit (instance: widget, signal_id: widget_signals[HIDE], detail: 0);
2797 g_object_notify_by_pspec (G_OBJECT (widget), pspec: widget_props[PROP_VISIBLE]);
2798
2799 gtk_accessible_update_state (self: GTK_ACCESSIBLE (ptr: widget),
2800 first_state: GTK_ACCESSIBLE_STATE_HIDDEN, TRUE,
2801 -1);
2802
2803 parent = gtk_widget_get_parent (widget);
2804 if (parent)
2805 gtk_widget_queue_resize (widget: parent);
2806
2807 gtk_widget_queue_allocate (widget);
2808
2809 gtk_widget_pop_verify_invariants (widget);
2810 g_object_unref (object: widget);
2811 }
2812}
2813
2814static void
2815gtk_widget_real_hide (GtkWidget *widget)
2816{
2817 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
2818
2819 g_return_if_fail (_gtk_widget_get_visible (widget));
2820
2821 priv->visible = FALSE;
2822
2823 if (_gtk_widget_get_mapped (widget))
2824 gtk_widget_unmap (widget);
2825
2826 g_clear_pointer (&priv->allocated_transform, gsk_transform_unref);
2827 priv->allocated_width = 0;
2828 priv->allocated_height = 0;
2829 priv->allocated_size_baseline = 0;
2830 g_clear_pointer (&priv->transform, gsk_transform_unref);
2831 priv->width = 0;
2832 priv->height = 0;
2833 gtk_widget_update_paintables (widget);
2834}
2835
2836static void
2837update_cursor_on_state_change (GtkWidget *widget)
2838{
2839 GtkRoot *root;
2840
2841 root = _gtk_widget_get_root (widget);
2842 if (GTK_IS_WINDOW (root))
2843 gtk_window_update_pointer_focus_on_state_change (GTK_WINDOW (root), widget);
2844}
2845
2846/**
2847 * gtk_widget_map:
2848 * @widget: a `GtkWidget`
2849 *
2850 * Causes a widget to be mapped if it isn’t already.
2851 *
2852 * This function is only for use in widget implementations.
2853 */
2854void
2855gtk_widget_map (GtkWidget *widget)
2856{
2857 g_return_if_fail (GTK_IS_WIDGET (widget));
2858 g_return_if_fail (_gtk_widget_get_visible (widget));
2859 g_return_if_fail (_gtk_widget_get_child_visible (widget));
2860
2861 if (!_gtk_widget_get_mapped (widget))
2862 {
2863 gtk_widget_push_verify_invariants (widget);
2864
2865 if (!_gtk_widget_get_realized (widget))
2866 gtk_widget_realize (widget);
2867
2868 g_signal_emit (instance: widget, signal_id: widget_signals[MAP], detail: 0);
2869
2870 update_cursor_on_state_change (widget);
2871
2872 gtk_widget_queue_draw (widget);
2873
2874 gtk_widget_pop_verify_invariants (widget);
2875 }
2876}
2877
2878/**
2879 * gtk_widget_unmap:
2880 * @widget: a `GtkWidget`
2881 *
2882 * Causes a widget to be unmapped if it’s currently mapped.
2883 *
2884 * This function is only for use in widget implementations.
2885 */
2886void
2887gtk_widget_unmap (GtkWidget *widget)
2888{
2889 g_return_if_fail (GTK_IS_WIDGET (widget));
2890
2891 if (_gtk_widget_get_mapped (widget))
2892 {
2893 g_object_ref (widget);
2894 gtk_widget_push_verify_invariants (widget);
2895
2896 gtk_widget_queue_draw (widget);
2897 _gtk_tooltip_hide (widget);
2898
2899 g_signal_emit (instance: widget, signal_id: widget_signals[UNMAP], detail: 0);
2900
2901 update_cursor_on_state_change (widget);
2902
2903 gtk_widget_pop_verify_invariants (widget);
2904 g_object_unref (object: widget);
2905 }
2906}
2907
2908typedef struct _GtkTickCallbackInfo GtkTickCallbackInfo;
2909
2910struct _GtkTickCallbackInfo
2911{
2912 guint refcount;
2913
2914 guint id;
2915 GtkTickCallback callback;
2916 gpointer user_data;
2917 GDestroyNotify notify;
2918
2919 guint destroyed : 1;
2920};
2921
2922static void
2923ref_tick_callback_info (GtkTickCallbackInfo *info)
2924{
2925 info->refcount++;
2926}
2927
2928static void
2929unref_tick_callback_info (GtkWidget *widget,
2930 GtkTickCallbackInfo *info,
2931 GList *link)
2932{
2933 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
2934
2935 info->refcount--;
2936 if (info->refcount == 0)
2937 {
2938 priv->tick_callbacks = g_list_delete_link (list: priv->tick_callbacks, link_: link);
2939 if (info->notify)
2940 info->notify (info->user_data);
2941 g_slice_free (GtkTickCallbackInfo, info);
2942 }
2943
2944 if (priv->tick_callbacks == NULL && priv->clock_tick_id)
2945 {
2946 GdkFrameClock *frame_clock = gtk_widget_get_frame_clock (widget);
2947 g_signal_handler_disconnect (instance: frame_clock, handler_id: priv->clock_tick_id);
2948 priv->clock_tick_id = 0;
2949 gdk_frame_clock_end_updating (frame_clock);
2950 }
2951}
2952
2953static void
2954destroy_tick_callback_info (GtkWidget *widget,
2955 GtkTickCallbackInfo *info,
2956 GList *link)
2957{
2958 if (!info->destroyed)
2959 {
2960 info->destroyed = TRUE;
2961 unref_tick_callback_info (widget, info, link);
2962 }
2963}
2964
2965static void
2966destroy_tick_callbacks (GtkWidget *widget)
2967{
2968 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
2969 GList *l;
2970
2971 for (l = priv->tick_callbacks; l;)
2972 {
2973 GList *next = l->next;
2974 destroy_tick_callback_info (widget, info: l->data, link: l);
2975 l = next;
2976 }
2977}
2978
2979static void
2980gtk_widget_on_frame_clock_update (GdkFrameClock *frame_clock,
2981 GtkWidget *widget)
2982{
2983 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
2984 GList *l;
2985
2986 g_object_ref (widget);
2987
2988 for (l = priv->tick_callbacks; l;)
2989 {
2990 GtkTickCallbackInfo *info = l->data;
2991 GList *next;
2992
2993 ref_tick_callback_info (info);
2994 if (!info->destroyed)
2995 {
2996 if (info->callback (widget,
2997 frame_clock,
2998 info->user_data) == G_SOURCE_REMOVE)
2999 {
3000 destroy_tick_callback_info (widget, info, link: l);
3001 }
3002 }
3003
3004 next = l->next;
3005 unref_tick_callback_info (widget, info, link: l);
3006 l = next;
3007 }
3008
3009 g_object_unref (object: widget);
3010}
3011
3012static guint tick_callback_id;
3013
3014/**
3015 * gtk_widget_add_tick_callback:
3016 * @widget: a `GtkWidget`
3017 * @callback: function to call for updating animations
3018 * @user_data: (closure): data to pass to @callback
3019 * @notify: function to call to free @user_data when the callback is removed.
3020 *
3021 * Queues an animation frame update and adds a callback to be called
3022 * before each frame.
3023 *
3024 * Until the tick callback is removed, it will be called frequently
3025 * (usually at the frame rate of the output device or as quickly as
3026 * the application can be repainted, whichever is slower). For this
3027 * reason, is most suitable for handling graphics that change every
3028 * frame or every few frames. The tick callback does not automatically
3029 * imply a relayout or repaint. If you want a repaint or relayout, and
3030 * aren’t changing widget properties that would trigger that (for example,
3031 * changing the text of a `GtkLabel`), then you will have to call
3032 * [method@Gtk.Widget.queue_resize] or [method@Gtk.Widget.queue_draw]
3033 * yourself.
3034 *
3035 * [method@Gdk.FrameClock.get_frame_time] should generally be used
3036 * for timing continuous animations and
3037 * [method@Gdk.FrameTimings.get_predicted_presentation_time] if you are
3038 * trying to display isolated frames at particular times.
3039 *
3040 * This is a more convenient alternative to connecting directly to the
3041 * [signal@Gdk.FrameClock::update] signal of `GdkFrameClock`, since you
3042 * don't have to worry about when a `GdkFrameClock` is assigned to a widget.
3043 *
3044 * Returns: an id for the connection of this callback. Remove the callback
3045 * by passing the id returned from this function to
3046 * [method@Gtk.Widget.remove_tick_callback]
3047 */
3048guint
3049gtk_widget_add_tick_callback (GtkWidget *widget,
3050 GtkTickCallback callback,
3051 gpointer user_data,
3052 GDestroyNotify notify)
3053{
3054 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
3055 GtkTickCallbackInfo *info;
3056 GdkFrameClock *frame_clock;
3057
3058 g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
3059
3060 if (priv->realized && !priv->clock_tick_id)
3061 {
3062 frame_clock = gtk_widget_get_frame_clock (widget);
3063
3064 if (frame_clock)
3065 {
3066 priv->clock_tick_id = g_signal_connect (frame_clock, "update",
3067 G_CALLBACK (gtk_widget_on_frame_clock_update),
3068 widget);
3069 gdk_frame_clock_begin_updating (frame_clock);
3070 }
3071 }
3072
3073 info = g_slice_new0 (GtkTickCallbackInfo);
3074
3075 info->refcount = 1;
3076 info->id = ++tick_callback_id;
3077 info->callback = callback;
3078 info->user_data = user_data;
3079 info->notify = notify;
3080
3081 priv->tick_callbacks = g_list_prepend (list: priv->tick_callbacks,
3082 data: info);
3083
3084 return info->id;
3085}
3086
3087/**
3088 * gtk_widget_remove_tick_callback:
3089 * @widget: a `GtkWidget`
3090 * @id: an id returned by [method@Gtk.Widget.add_tick_callback]
3091 *
3092 * Removes a tick callback previously registered with
3093 * gtk_widget_add_tick_callback().
3094 */
3095void
3096gtk_widget_remove_tick_callback (GtkWidget *widget,
3097 guint id)
3098{
3099 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
3100 GList *l;
3101
3102 g_return_if_fail (GTK_IS_WIDGET (widget));
3103
3104 for (l = priv->tick_callbacks; l; l = l->next)
3105 {
3106 GtkTickCallbackInfo *info = l->data;
3107 if (info->id == id)
3108 {
3109 destroy_tick_callback_info (widget, info, link: l);
3110 return;
3111 }
3112 }
3113}
3114
3115gboolean
3116gtk_widget_has_tick_callback (GtkWidget *widget)
3117{
3118 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
3119
3120 return priv->tick_callbacks != NULL;
3121}
3122
3123typedef struct _GtkSurfaceTransformChangedCallbackInfo GtkSurfaceTransformChangedCallbackInfo;
3124
3125struct _GtkSurfaceTransformChangedCallbackInfo
3126{
3127 guint id;
3128 GtkSurfaceTransformChangedCallback callback;
3129 gpointer user_data;
3130 GDestroyNotify notify;
3131};
3132
3133static void
3134surface_transform_changed_callback_info_destroy (GtkSurfaceTransformChangedCallbackInfo *info)
3135{
3136 if (info->notify)
3137 info->notify (info->user_data);
3138
3139 g_slice_free (GtkSurfaceTransformChangedCallbackInfo, info);
3140}
3141
3142static void
3143notify_surface_transform_changed (GtkWidget *widget)
3144{
3145 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
3146 GtkWidgetSurfaceTransformData *surface_transform_data =
3147 priv->surface_transform_data;
3148 graphene_matrix_t *surface_transform;
3149 GList *l;
3150
3151 if (surface_transform_data->cached_surface_transform_valid)
3152 surface_transform = &surface_transform_data->cached_surface_transform;
3153 else
3154 surface_transform = NULL;
3155
3156 for (l = surface_transform_data->callbacks; l;)
3157 {
3158 GtkSurfaceTransformChangedCallbackInfo *info = l->data;
3159 GList *l_next = l->next;
3160
3161 if (info->callback (widget,
3162 surface_transform,
3163 info->user_data) == G_SOURCE_REMOVE)
3164 {
3165 surface_transform_data->callbacks =
3166 g_list_delete_link (list: surface_transform_data->callbacks, link_: l);
3167 surface_transform_changed_callback_info_destroy (info);
3168 }
3169
3170 l = l_next;
3171 }
3172}
3173
3174static void
3175destroy_surface_transform_data (GtkWidget *widget)
3176{
3177 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
3178 GtkWidgetSurfaceTransformData *surface_transform_data;
3179
3180 surface_transform_data = priv->surface_transform_data;
3181 if (!surface_transform_data)
3182 return;
3183
3184 g_list_free_full (list: surface_transform_data->callbacks,
3185 free_func: (GDestroyNotify) surface_transform_changed_callback_info_destroy);
3186 g_slice_free (GtkWidgetSurfaceTransformData, surface_transform_data);
3187 priv->surface_transform_data = NULL;
3188}
3189
3190static void
3191sync_widget_surface_transform (GtkWidget *widget)
3192{
3193 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
3194 GtkWidgetSurfaceTransformData *surface_transform_data =
3195 priv->surface_transform_data;
3196 gboolean was_valid;
3197 graphene_matrix_t prev_transform;
3198
3199 was_valid = surface_transform_data->cached_surface_transform_valid;
3200 prev_transform = surface_transform_data->cached_surface_transform;
3201
3202 if (GTK_IS_NATIVE (ptr: widget))
3203 {
3204 gsk_transform_to_matrix (self: priv->transform,
3205 out_matrix: &surface_transform_data->cached_surface_transform);
3206 surface_transform_data->cached_surface_transform_valid = TRUE;
3207 }
3208 else if (!priv->root)
3209 {
3210 surface_transform_data->cached_surface_transform_valid = FALSE;
3211 }
3212 else
3213 {
3214 GtkWidget *native = GTK_WIDGET (gtk_widget_get_native (widget));
3215
3216 if (gtk_widget_compute_transform (widget, target: native,
3217 out_transform: &surface_transform_data->cached_surface_transform))
3218 {
3219 surface_transform_data->cached_surface_transform_valid = TRUE;
3220 }
3221 else
3222 {
3223 g_warning ("Could not compute surface transform");
3224 surface_transform_data->cached_surface_transform_valid = FALSE;
3225 }
3226 }
3227
3228 if (was_valid != surface_transform_data->cached_surface_transform_valid ||
3229 (was_valid && surface_transform_data->cached_surface_transform_valid &&
3230 !graphene_matrix_equal (a: &surface_transform_data->cached_surface_transform,
3231 b: &prev_transform)))
3232 notify_surface_transform_changed (widget);
3233}
3234
3235static guint surface_transform_changed_callback_id;
3236
3237static gboolean
3238parent_surface_transform_changed_cb (GtkWidget *parent,
3239 const graphene_matrix_t *transform,
3240 gpointer user_data)
3241{
3242 GtkWidget *widget = GTK_WIDGET (user_data);
3243
3244 sync_widget_surface_transform (widget);
3245
3246 return G_SOURCE_CONTINUE;
3247}
3248
3249static void
3250remove_parent_surface_transform_changed_listener (GtkWidget *widget)
3251{
3252 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
3253 GtkWidgetSurfaceTransformData *surface_transform_data =
3254 priv->surface_transform_data;
3255
3256 g_assert (surface_transform_data->tracked_parent);
3257
3258 gtk_widget_remove_surface_transform_changed_callback (
3259 widget: surface_transform_data->tracked_parent,
3260 id: surface_transform_data->parent_surface_transform_changed_id);
3261 surface_transform_data->parent_surface_transform_changed_id = 0;
3262 g_clear_object (&surface_transform_data->tracked_parent);
3263}
3264
3265static void
3266add_parent_surface_transform_changed_listener (GtkWidget *widget)
3267{
3268 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
3269 GtkWidgetSurfaceTransformData *surface_transform_data =
3270 priv->surface_transform_data;
3271 GtkWidget *parent;
3272
3273
3274 g_assert (!surface_transform_data->tracked_parent);
3275
3276 parent = priv->parent;
3277 surface_transform_data->parent_surface_transform_changed_id =
3278 gtk_widget_add_surface_transform_changed_callback (
3279 widget: parent,
3280 callback: parent_surface_transform_changed_cb,
3281 user_data: widget,
3282 NULL);
3283 surface_transform_data->tracked_parent = g_object_ref (parent);
3284}
3285
3286static GtkWidgetSurfaceTransformData *
3287ensure_surface_transform_data (GtkWidget *widget)
3288{
3289 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
3290
3291 if (!priv->surface_transform_data)
3292 priv->surface_transform_data = g_slice_new0 (GtkWidgetSurfaceTransformData);
3293
3294 return priv->surface_transform_data;
3295}
3296
3297/**
3298 * gtk_widget_add_surface_transform_changed_callback:
3299 * @widget: a `GtkWidget`
3300 * @callback: a function to call when the surface transform changes
3301 * @user_data: (closure): data to pass to @callback
3302 * @notify: function to call to free @user_data when the callback is removed
3303 *
3304 * Invokes the callback whenever the surface relative transform of
3305 * the widget changes.
3306 *
3307 * Returns: an id for the connection of this callback. Remove the
3308 * callback by passing the id returned from this function to
3309 * [method@Gtk.Widget.remove_surface_transform_changed_callback]
3310 */
3311guint
3312gtk_widget_add_surface_transform_changed_callback (GtkWidget *widget,
3313 GtkSurfaceTransformChangedCallback callback,
3314 gpointer user_data,
3315 GDestroyNotify notify)
3316{
3317 GtkWidgetPrivate *priv;
3318 GtkWidgetSurfaceTransformData *surface_transform_data;
3319 GtkSurfaceTransformChangedCallbackInfo *info;
3320
3321 g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
3322 g_return_val_if_fail (callback, 0);
3323
3324 priv = gtk_widget_get_instance_private (self: widget);
3325 surface_transform_data = ensure_surface_transform_data (widget);
3326
3327 if (priv->parent &&
3328 !surface_transform_data->parent_surface_transform_changed_id)
3329 add_parent_surface_transform_changed_listener (widget);
3330
3331 if (!surface_transform_data->callbacks)
3332 sync_widget_surface_transform (widget);
3333
3334 info = g_slice_new0 (GtkSurfaceTransformChangedCallbackInfo);
3335
3336 info->id = ++surface_transform_changed_callback_id;
3337 info->callback = callback;
3338 info->user_data = user_data;
3339 info->notify = notify;
3340
3341 surface_transform_data->callbacks =
3342 g_list_prepend (list: surface_transform_data->callbacks, data: info);
3343
3344 return info->id;
3345}
3346
3347/**
3348 * gtk_widget_remove_surface_transform_changed_callback:
3349 * @widget: a `GtkWidget`
3350 * @id: an id returned by [method@Gtk.Widget.add_surface_transform_changed_callback]
3351 *
3352 * Removes a surface transform changed callback previously registered with
3353 * gtk_widget_add_surface_transform_changed_callback().
3354 */
3355void
3356gtk_widget_remove_surface_transform_changed_callback (GtkWidget *widget,
3357 guint id)
3358{
3359 GtkWidgetPrivate *priv;
3360 GtkWidgetSurfaceTransformData *surface_transform_data;
3361 GList *l;
3362
3363 g_return_if_fail (GTK_IS_WIDGET (widget));
3364 g_return_if_fail (id);
3365
3366 priv = gtk_widget_get_instance_private (self: widget);
3367 surface_transform_data = priv->surface_transform_data;
3368
3369 g_return_if_fail (surface_transform_data);
3370
3371 for (l = surface_transform_data->callbacks; l; l = l->next)
3372 {
3373 GtkSurfaceTransformChangedCallbackInfo *info = l->data;
3374
3375 if (info->id == id)
3376 {
3377 surface_transform_data->callbacks =
3378 g_list_delete_link (list: surface_transform_data->callbacks, link_: l);
3379
3380 surface_transform_changed_callback_info_destroy (info);
3381 break;
3382 }
3383 }
3384
3385 if (!surface_transform_data->callbacks)
3386 {
3387 if (surface_transform_data->tracked_parent)
3388 remove_parent_surface_transform_changed_listener (widget);
3389 g_slice_free (GtkWidgetSurfaceTransformData, surface_transform_data);
3390 priv->surface_transform_data = NULL;
3391 }
3392}
3393
3394GdkSurface *
3395gtk_widget_get_surface (GtkWidget *widget)
3396{
3397 GtkNative *native = gtk_widget_get_native (widget);
3398
3399 if (native)
3400 return gtk_native_get_surface (self: native);
3401
3402 return NULL;
3403}
3404
3405/**
3406 * gtk_widget_realize:
3407 * @widget: a `GtkWidget`
3408 *
3409 * Creates the GDK resources associated with a widget.
3410 *
3411 * Normally realization happens implicitly; if you show a widget
3412 * and all its parent containers, then the widget will be realized
3413 * and mapped automatically.
3414 *
3415 * Realizing a widget requires all the widget’s parent widgets to be
3416 * realized; calling this function realizes the widget’s parents
3417 * in addition to @widget itself. If a widget is not yet inside a
3418 * toplevel window when you realize it, bad things will happen.
3419 *
3420 * This function is primarily used in widget implementations, and
3421 * isn’t very useful otherwise. Many times when you think you might
3422 * need it, a better approach is to connect to a signal that will be
3423 * called after the widget is realized automatically, such as
3424 * [signal@Gtk.Widget::realize].
3425 */
3426void
3427gtk_widget_realize (GtkWidget *widget)
3428{
3429 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
3430
3431 g_return_if_fail (GTK_IS_WIDGET (widget));
3432
3433 if (priv->realized)
3434 return;
3435
3436 gtk_widget_push_verify_invariants (widget);
3437
3438 /*
3439 if (GTK_IS_CONTAINER (widget) && _gtk_widget_get_has_surface (widget))
3440 g_message ("gtk_widget_realize(%s)", G_OBJECT_TYPE_NAME (widget));
3441 */
3442
3443 if (priv->parent == NULL && !GTK_IS_ROOT (ptr: widget))
3444 g_warning ("Calling gtk_widget_realize() on a widget that isn't "
3445 "inside a toplevel window is not going to work very well. "
3446 "Widgets must be inside a toplevel container before realizing them.");
3447
3448 if (priv->parent && !_gtk_widget_get_realized (widget: priv->parent))
3449 gtk_widget_realize (widget: priv->parent);
3450
3451 g_signal_emit (instance: widget, signal_id: widget_signals[REALIZE], detail: 0);
3452
3453 if (priv->context)
3454 gtk_style_context_set_scale (context: priv->context, scale: gtk_widget_get_scale_factor (widget));
3455 else
3456 gtk_widget_get_style_context (widget);
3457
3458 gtk_widget_pop_verify_invariants (widget);
3459}
3460
3461/**
3462 * gtk_widget_unrealize:
3463 * @widget: a `GtkWidget`
3464 *
3465 * Causes a widget to be unrealized (frees all GDK resources
3466 * associated with the widget).
3467 *
3468 * This function is only useful in widget implementations.
3469 */
3470void
3471gtk_widget_unrealize (GtkWidget *widget)
3472{
3473 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
3474
3475 g_return_if_fail (GTK_IS_WIDGET (widget));
3476
3477 g_object_ref (widget);
3478 gtk_widget_push_verify_invariants (widget);
3479
3480 if (_gtk_widget_get_realized (widget))
3481 {
3482 if (priv->mapped)
3483 gtk_widget_unmap (widget);
3484
3485 g_signal_emit (instance: widget, signal_id: widget_signals[UNREALIZE], detail: 0);
3486 g_assert (!priv->mapped);
3487 g_assert (!priv->realized);
3488 }
3489
3490 gtk_widget_pop_verify_invariants (widget);
3491 g_object_unref (object: widget);
3492}
3493
3494void
3495gtk_widget_get_surface_allocation (GtkWidget *widget,
3496 GtkAllocation *allocation)
3497{
3498 GtkNative *native;
3499 graphene_rect_t bounds;
3500 double nx, ny;
3501
3502 native = gtk_widget_get_native (widget);
3503
3504 g_assert (GTK_IS_WINDOW (native) || GTK_IS_POPOVER (native));
3505 gtk_native_get_surface_transform (self: native, x: &nx, y: &ny);
3506
3507 if (gtk_widget_compute_bounds (widget, GTK_WIDGET (native), out_bounds: &bounds))
3508 {
3509 *allocation = (GtkAllocation) {
3510 floorf (x: bounds.origin.x) + nx,
3511 floorf (x: bounds.origin.y) + ny,
3512 ceilf (x: bounds.size.width),
3513 ceilf (x: bounds.size.height)
3514 };
3515 }
3516 else
3517 {
3518 *allocation = (GtkAllocation) { 0, 0, 0, 0 };
3519 }
3520}
3521
3522/**
3523 * gtk_widget_queue_draw:
3524 * @widget: a `GtkWidget`
3525 *
3526 * Schedules this widget to be redrawn in the paint phase
3527 * of the current or the next frame.
3528 *
3529 * This means @widget's [vfunc@Gtk.Widget.snapshot]
3530 * implementation will be called.
3531 */
3532void
3533gtk_widget_queue_draw (GtkWidget *widget)
3534{
3535 g_return_if_fail (GTK_IS_WIDGET (widget));
3536
3537 /* Just return if the widget isn't mapped */
3538 if (!_gtk_widget_get_mapped (widget))
3539 return;
3540
3541 for (; widget; widget = _gtk_widget_get_parent (widget))
3542 {
3543 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
3544
3545 if (priv->draw_needed)
3546 break;
3547
3548 priv->draw_needed = TRUE;
3549 g_clear_pointer (&priv->render_node, gsk_render_node_unref);
3550 if (GTK_IS_NATIVE (ptr: widget) && _gtk_widget_get_realized (widget))
3551 gdk_surface_queue_render (surface: gtk_native_get_surface (self: GTK_NATIVE (ptr: widget)));
3552 }
3553}
3554
3555static void
3556gtk_widget_set_alloc_needed (GtkWidget *widget);
3557
3558/**
3559 * gtk_widget_queue_allocate:
3560 * @widget: a `GtkWidget`
3561 *
3562 * Flags the widget for a rerun of the [vfunc@Gtk.Widget.size_allocate]
3563 * function.
3564 *
3565 * Use this function instead of [method@Gtk.Widget.queue_resize]
3566 * when the @widget's size request didn't change but it wants to
3567 * reposition its contents.
3568 *
3569 * An example user of this function is [method@Gtk.Widget.set_halign].
3570 *
3571 * This function is only for use in widget implementations.
3572 */
3573void
3574gtk_widget_queue_allocate (GtkWidget *widget)
3575{
3576 g_return_if_fail (GTK_IS_WIDGET (widget));
3577
3578 if (_gtk_widget_get_realized (widget))
3579 gtk_widget_queue_draw (widget);
3580
3581 gtk_widget_set_alloc_needed (widget);
3582}
3583
3584static inline gboolean
3585gtk_widget_get_resize_needed (GtkWidget *widget)
3586{
3587 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
3588
3589 return priv->resize_needed;
3590}
3591
3592/*
3593 * gtk_widget_queue_resize_internal:
3594 * @widget: a `GtkWidget`
3595 *
3596 * Queue a resize on a widget, and on all other widgets
3597 * grouped with this widget.
3598 */
3599static void
3600gtk_widget_queue_resize_internal (GtkWidget *widget)
3601{
3602 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
3603 GSList *groups, *l, *widgets;
3604
3605 if (gtk_widget_get_resize_needed (widget))
3606 return;
3607
3608 priv->resize_needed = TRUE;
3609 _gtk_size_request_cache_clear (cache: &priv->requests);
3610 gtk_widget_set_alloc_needed (widget);
3611
3612 if (priv->resize_func)
3613 priv->resize_func (widget);
3614
3615 groups = _gtk_widget_get_sizegroups (widget);
3616
3617 for (l = groups; l; l = l->next)
3618 {
3619 for (widgets = gtk_size_group_get_widgets (size_group: l->data); widgets; widgets = widgets->next)
3620 gtk_widget_queue_resize_internal (widget: widgets->data);
3621 }
3622
3623 if (_gtk_widget_get_visible (widget))
3624 {
3625 GtkWidget *parent = _gtk_widget_get_parent (widget);
3626 if (parent)
3627 {
3628 if (GTK_IS_NATIVE (ptr: widget))
3629 gtk_widget_queue_allocate (widget: parent);
3630 else
3631 gtk_widget_queue_resize_internal (widget: parent);
3632 }
3633 }
3634}
3635
3636/**
3637 * gtk_widget_queue_resize:
3638 * @widget: a `GtkWidget`
3639 *
3640 * Flags a widget to have its size renegotiated.
3641 *
3642 * This should be called when a widget for some reason has a new
3643 * size request. For example, when you change the text in a
3644 * [class@Gtk.Label], the label queues a resize to ensure there’s
3645 * enough space for the new text.
3646 *
3647 * Note that you cannot call gtk_widget_queue_resize() on a widget
3648 * from inside its implementation of the [vfunc@Gtk.Widget.size_allocate]
3649 * virtual method. Calls to gtk_widget_queue_resize() from inside
3650 * [vfunc@Gtk.Widget.size_allocate] will be silently ignored.
3651 *
3652 * This function is only for use in widget implementations.
3653 */
3654void
3655gtk_widget_queue_resize (GtkWidget *widget)
3656{
3657 g_return_if_fail (GTK_IS_WIDGET (widget));
3658
3659 if (_gtk_widget_get_realized (widget))
3660 gtk_widget_queue_draw (widget);
3661
3662 gtk_widget_queue_resize_internal (widget);
3663}
3664
3665/**
3666 * gtk_widget_get_frame_clock:
3667 * @widget: a `GtkWidget`
3668 *
3669 * Obtains the frame clock for a widget.
3670 *
3671 * The frame clock is a global “ticker” that can be used to drive
3672 * animations and repaints. The most common reason to get the frame
3673 * clock is to call [method@Gdk.FrameClock.get_frame_time], in order
3674 * to get a time to use for animating. For example you might record
3675 * the start of the animation with an initial value from
3676 * [method@Gdk.FrameClock.get_frame_time], and then update the animation
3677 * by calling [method@Gdk.FrameClock.get_frame_time] again during each repaint.
3678 *
3679 * [method@Gdk.FrameClock.request_phase] will result in a new frame on the
3680 * clock, but won’t necessarily repaint any widgets. To repaint a
3681 * widget, you have to use [method@Gtk.Widget.queue_draw] which invalidates
3682 * the widget (thus scheduling it to receive a draw on the next
3683 * frame). gtk_widget_queue_draw() will also end up requesting a frame
3684 * on the appropriate frame clock.
3685 *
3686 * A widget’s frame clock will not change while the widget is
3687 * mapped. Reparenting a widget (which implies a temporary unmap) can
3688 * change the widget’s frame clock.
3689 *
3690 * Unrealized widgets do not have a frame clock.
3691 *
3692 * Returns: (nullable) (transfer none): a `GdkFrameClock`
3693 */
3694GdkFrameClock*
3695gtk_widget_get_frame_clock (GtkWidget *widget)
3696{
3697 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
3698
3699 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
3700
3701 if (priv->realized)
3702 {
3703 GdkSurface *surface = gtk_widget_get_surface (widget);
3704
3705 return gdk_surface_get_frame_clock (surface);
3706 }
3707 else
3708 {
3709 return NULL;
3710 }
3711}
3712
3713static int
3714get_number (GtkCssValue *value)
3715{
3716 double d = _gtk_css_number_value_get (number: value, one_hundred_percent: 100);
3717
3718 if (d < 1)
3719 return ceil (x: d);
3720 else
3721 return floor (x: d);
3722}
3723
3724static void
3725get_box_margin (GtkCssStyle *style,
3726 GtkBorder *margin)
3727{
3728 margin->top = get_number (value: style->size->margin_top);
3729 margin->left = get_number (value: style->size->margin_left);
3730 margin->bottom = get_number (value: style->size->margin_bottom);
3731 margin->right = get_number (value: style->size->margin_right);
3732}
3733
3734static void
3735get_box_border (GtkCssStyle *style,
3736 GtkBorder *border)
3737{
3738 border->top = get_number (value: style->border->border_top_width);
3739 border->left = get_number (value: style->border->border_left_width);
3740 border->bottom = get_number (value: style->border->border_bottom_width);
3741 border->right = get_number (value: style->border->border_right_width);
3742}
3743
3744static void
3745get_box_padding (GtkCssStyle *style,
3746 GtkBorder *border)
3747{
3748 border->top = get_number (value: style->size->padding_top);
3749 border->left = get_number (value: style->size->padding_left);
3750 border->bottom = get_number (value: style->size->padding_bottom);
3751 border->right = get_number (value: style->size->padding_right);
3752}
3753
3754/**
3755 * gtk_widget_size_allocate:
3756 * @widget: a `GtkWidget`
3757 * @allocation: position and size to be allocated to @widget
3758 * @baseline: The baseline of the child, or -1
3759 *
3760 * Allocates widget with a transformation that translates
3761 * the origin to the position in @allocation.
3762 *
3763 * This is a simple form of [method@Gtk.Widget.allocate].
3764 */
3765void
3766gtk_widget_size_allocate (GtkWidget *widget,
3767 const GtkAllocation *allocation,
3768 int baseline)
3769{
3770 GskTransform *transform;
3771
3772 if (allocation->x || allocation->y)
3773 transform = gsk_transform_translate (NULL, point: &GRAPHENE_POINT_INIT (allocation->x, allocation->y));
3774 else
3775 transform = NULL;
3776
3777 gtk_widget_allocate (widget,
3778 width: allocation->width,
3779 height: allocation->height,
3780 baseline,
3781 transform);
3782}
3783
3784/* translate initial/final into start/end */
3785static GtkAlign
3786effective_align (GtkAlign align,
3787 GtkTextDirection direction)
3788{
3789 switch (align)
3790 {
3791 case GTK_ALIGN_START:
3792 return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_END : GTK_ALIGN_START;
3793 case GTK_ALIGN_END:
3794 return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_START : GTK_ALIGN_END;
3795 case GTK_ALIGN_FILL:
3796 case GTK_ALIGN_CENTER:
3797 case GTK_ALIGN_BASELINE:
3798 default:
3799 return align;
3800 }
3801}
3802
3803static void
3804adjust_for_align (GtkAlign align,
3805 int natural_size,
3806 int *allocated_pos,
3807 int *allocated_size)
3808{
3809 switch (align)
3810 {
3811 case GTK_ALIGN_BASELINE:
3812 case GTK_ALIGN_FILL:
3813 default:
3814 /* change nothing */
3815 break;
3816 case GTK_ALIGN_START:
3817 /* keep *allocated_pos where it is */
3818 *allocated_size = MIN (*allocated_size, natural_size);
3819 break;
3820 case GTK_ALIGN_END:
3821 if (*allocated_size > natural_size)
3822 {
3823 *allocated_pos += (*allocated_size - natural_size);
3824 *allocated_size = natural_size;
3825 }
3826 break;
3827 case GTK_ALIGN_CENTER:
3828 if (*allocated_size > natural_size)
3829 {
3830 *allocated_pos += (*allocated_size - natural_size) / 2;
3831 *allocated_size = MIN (*allocated_size, natural_size);
3832 }
3833 break;
3834 }
3835}
3836
3837static inline void
3838gtk_widget_adjust_size_allocation (GtkWidget *widget,
3839 GtkAllocation *allocation)
3840{
3841 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
3842 int natural_width, natural_height;
3843 int min_width, min_height;
3844
3845 if (priv->halign == GTK_ALIGN_FILL && priv->valign == GTK_ALIGN_FILL)
3846 return;
3847
3848 /* Note that adjust_for_align removes any margins from the
3849 * allocated sizes and possibly limits them to the natural sizes */
3850
3851 if (priv->halign == GTK_ALIGN_FILL ||
3852 (priv->valign != GTK_ALIGN_FILL &&
3853 gtk_widget_get_request_mode (widget) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH))
3854 {
3855 gtk_widget_measure (widget, orientation: GTK_ORIENTATION_HORIZONTAL,
3856 for_size: allocation->height + priv->margin.top + priv->margin.bottom,
3857 minimum: &min_width, NULL, NULL, NULL);
3858 gtk_widget_measure (widget, orientation: GTK_ORIENTATION_HORIZONTAL,
3859 for_size: -1,
3860 NULL, natural: &natural_width, NULL, NULL);
3861 natural_width = MAX (min_width, natural_width);
3862 adjust_for_align (align: effective_align (align: priv->halign, direction: _gtk_widget_get_direction (widget)),
3863 natural_size: natural_width - priv->margin.left - priv->margin.right,
3864 allocated_pos: &allocation->x,
3865 allocated_size: &allocation->width);
3866 gtk_widget_measure (widget, orientation: GTK_ORIENTATION_VERTICAL,
3867 for_size: allocation->width + priv->margin.left + priv->margin.right,
3868 minimum: &min_height, natural: &natural_height, NULL, NULL);
3869 adjust_for_align (align: priv->valign,
3870 natural_size: natural_height - priv->margin.top - priv->margin.bottom,
3871 allocated_pos: &allocation->y,
3872 allocated_size: &allocation->height);
3873 }
3874 else
3875 {
3876 gtk_widget_measure (widget, orientation: GTK_ORIENTATION_VERTICAL,
3877 for_size: allocation->width + priv->margin.left + priv->margin.right,
3878 minimum: &min_height, NULL, NULL, NULL);
3879 gtk_widget_measure (widget, orientation: GTK_ORIENTATION_VERTICAL,
3880 for_size: -1,
3881 NULL, natural: &natural_height, NULL, NULL);
3882 natural_height = MAX (min_height, natural_height);
3883 adjust_for_align (align: priv->valign,
3884 natural_size: natural_height - priv->margin.top - priv->margin.bottom,
3885 allocated_pos: &allocation->y,
3886 allocated_size: &allocation->height);
3887 gtk_widget_measure (widget, orientation: GTK_ORIENTATION_HORIZONTAL,
3888 for_size: allocation->height + priv->margin.top + priv->margin.bottom,
3889 minimum: &min_width, natural: &natural_width, NULL, NULL);
3890 adjust_for_align (align: effective_align (align: priv->halign, direction: _gtk_widget_get_direction (widget)),
3891 natural_size: natural_width - priv->margin.left - priv->margin.right,
3892 allocated_pos: &allocation->x,
3893 allocated_size: &allocation->width);
3894 }
3895}
3896
3897/**
3898 * gtk_widget_allocate:
3899 * @widget: A `GtkWidget`
3900 * @width: New width of @widget
3901 * @height: New height of @widget
3902 * @baseline: New baseline of @widget, or -1
3903 * @transform: (transfer full) (nullable): Transformation to be applied to @widget
3904 *
3905 * This function is only used by `GtkWidget` subclasses, to
3906 * assign a size, position and (optionally) baseline to their
3907 * child widgets.
3908 *
3909 * In this function, the allocation and baseline may be adjusted.
3910 * The given allocation will be forced to be bigger than the
3911 * widget's minimum size, as well as at least 0×0 in size.
3912 *
3913 * For a version that does not take a transform, see
3914 * [method@Gtk.Widget.size_allocate].
3915 */
3916void
3917gtk_widget_allocate (GtkWidget *widget,
3918 int width,
3919 int height,
3920 int baseline,
3921 GskTransform *transform)
3922{
3923 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
3924 GdkRectangle adjusted;
3925 gboolean alloc_needed;
3926 gboolean size_changed;
3927 gboolean baseline_changed;
3928 gboolean transform_changed;
3929 GtkCssStyle *style;
3930 GtkBorder margin, border, padding;
3931 GskTransform *css_transform;
3932
3933 g_return_if_fail (GTK_IS_WIDGET (widget));
3934 g_return_if_fail (baseline >= -1);
3935
3936 gtk_widget_push_verify_invariants (widget);
3937
3938 if (!priv->visible && !GTK_IS_ROOT (ptr: widget))
3939 {
3940 gsk_transform_unref (self: transform);
3941 goto out;
3942 }
3943
3944#ifdef G_ENABLE_DEBUG
3945 if (gtk_widget_get_resize_needed (widget))
3946 {
3947 g_warning ("Allocating size to %s %p without calling gtk_widget_measure(). "
3948 "How does the code know the size to allocate?",
3949 gtk_widget_get_name (widget), widget);
3950 }
3951 if (!GTK_IS_SCROLLABLE (widget))
3952 {
3953 int min;
3954 gtk_widget_measure (widget, orientation: GTK_ORIENTATION_VERTICAL, for_size: width, minimum: &min, NULL, NULL, NULL);
3955 if (min > height)
3956 {
3957 g_critical ("Allocation height too small. Tried to allocate %dx%d, but %s %p needs "
3958 "at least %dx%d.",
3959 width, height,
3960 gtk_widget_get_name (widget), widget,
3961 width, min);
3962 }
3963 gtk_widget_measure (widget, orientation: GTK_ORIENTATION_HORIZONTAL, for_size: height, minimum: &min, NULL, NULL, NULL);
3964 if (min > width)
3965 {
3966 g_critical ("Allocation width too small. Tried to allocate %dx%d, but %s %p needs "
3967 "at least %dx%d.",
3968 width, height,
3969 gtk_widget_get_name (widget), widget,
3970 min, height);
3971 }
3972 }
3973#endif /* G_ENABLE_DEBUG */
3974
3975 alloc_needed = priv->alloc_needed;
3976 /* Preserve request/allocate ordering */
3977 priv->alloc_needed = FALSE;
3978
3979 baseline_changed = priv->allocated_size_baseline != baseline;
3980 transform_changed = !gsk_transform_equal (first: priv->allocated_transform, second: transform);
3981
3982 gsk_transform_unref (self: priv->allocated_transform);
3983 priv->allocated_transform = gsk_transform_ref (self: transform);
3984 priv->allocated_width = width;
3985 priv->allocated_height = height;
3986 priv->allocated_size_baseline = baseline;
3987
3988 if (_gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
3989 adjusted.x = priv->margin.left;
3990 else
3991 adjusted.x = priv->margin.right;
3992 adjusted.y = priv->margin.top;
3993 adjusted.width = width - priv->margin.left - priv->margin.right;
3994 adjusted.height = height - priv->margin.top - priv->margin.bottom;
3995 if (baseline >= 0)
3996 baseline -= priv->margin.top;
3997
3998 gtk_widget_adjust_size_allocation (widget, allocation: &adjusted);
3999
4000 if (adjusted.width < 0 || adjusted.height < 0)
4001 {
4002 g_warning ("gtk_widget_size_allocate(): attempt to allocate %s %s %p with width %d and height %d",
4003 G_OBJECT_TYPE_NAME (widget), g_quark_to_string (gtk_css_node_get_name (priv->cssnode)), widget,
4004 adjusted.width,
4005 adjusted.height);
4006
4007 adjusted.width = 0;
4008 adjusted.height = 0;
4009 }
4010
4011 style = gtk_css_node_get_style (cssnode: priv->cssnode);
4012 get_box_margin (style, margin: &margin);
4013 get_box_border (style, border: &border);
4014 get_box_padding (style, border: &padding);
4015
4016 /* Apply CSS transformation */
4017 adjusted.x += margin.left;
4018 adjusted.y += margin.top;
4019 adjusted.width -= margin.left + margin.right;
4020 adjusted.height -= margin.top + margin.bottom;
4021 css_transform = gtk_css_transform_value_get_transform (transform: style->other->transform);
4022
4023 if (css_transform)
4024 {
4025 double origin_x, origin_y;
4026
4027 origin_x = _gtk_css_position_value_get_x (position: style->other->transform_origin, one_hundred_percent: adjusted.width);
4028 origin_y = _gtk_css_position_value_get_y (position: style->other->transform_origin, one_hundred_percent: adjusted.height);
4029
4030 transform = gsk_transform_translate (next: transform, point: &GRAPHENE_POINT_INIT (adjusted.x, adjusted.y));
4031 adjusted.x = adjusted.y = 0;
4032
4033 transform = gsk_transform_translate (next: transform, point: &GRAPHENE_POINT_INIT (origin_x, origin_y));
4034 transform = gsk_transform_transform (next: transform, other: css_transform);
4035 transform = gsk_transform_translate (next: transform, point: &GRAPHENE_POINT_INIT (- origin_x, - origin_y));
4036
4037 gsk_transform_unref (self: css_transform);
4038 }
4039
4040 adjusted.x += border.left + padding.left;
4041 adjusted.y += border.top + padding.top;
4042
4043 if (baseline >= 0)
4044 baseline -= margin.top + border.top + padding.top;
4045 if (adjusted.x || adjusted.y)
4046 transform = gsk_transform_translate (next: transform, point: &GRAPHENE_POINT_INIT (adjusted.x, adjusted.y));
4047
4048 gsk_transform_unref (self: priv->transform);
4049 priv->transform = transform;
4050
4051 if (priv->surface_transform_data)
4052 sync_widget_surface_transform (widget);
4053
4054 /* Since gtk_widget_measure does it for us, we can be sure here that
4055 * the given alloaction is large enough for the css margin/bordder/padding */
4056 adjusted.width -= border.left + padding.left +
4057 border.right + padding.right;
4058 adjusted.height -= border.top + padding.top +
4059 border.bottom + padding.bottom;
4060 size_changed = (priv->width != adjusted.width) || (priv->height != adjusted.height);
4061
4062 if (!alloc_needed && !size_changed && !baseline_changed)
4063 goto skip_allocate;
4064
4065 priv->width = adjusted.width;
4066 priv->height = adjusted.height;
4067 priv->baseline = baseline;
4068
4069 if (priv->layout_manager != NULL)
4070 {
4071 gtk_layout_manager_allocate (manager: priv->layout_manager, widget,
4072 width: priv->width,
4073 height: priv->height,
4074 baseline);
4075 }
4076 else
4077 {
4078 GTK_WIDGET_GET_CLASS (widget)->size_allocate (widget,
4079 priv->width,
4080 priv->height,
4081 baseline);
4082 }
4083
4084 /* Size allocation is god... after consulting god, no further requests or allocations are needed */
4085#ifdef G_ENABLE_DEBUG
4086 if (GTK_DISPLAY_DEBUG_CHECK (_gtk_widget_get_display (widget), GEOMETRY) &&
4087 gtk_widget_get_resize_needed (widget))
4088 {
4089 g_warning ("%s %p or a child called gtk_widget_queue_resize() during size_allocate().",
4090 gtk_widget_get_name (widget), widget);
4091 }
4092#endif
4093
4094 gtk_widget_ensure_resize (widget);
4095 priv->alloc_needed = FALSE;
4096 priv->alloc_needed_on_child = FALSE;
4097
4098 gtk_widget_update_paintables (widget);
4099
4100 if (size_changed)
4101 gtk_accessible_bounds_changed (self: GTK_ACCESSIBLE (ptr: widget));
4102
4103skip_allocate:
4104 if (size_changed || baseline_changed)
4105 gtk_widget_queue_draw (widget);
4106 else if (transform_changed && priv->parent)
4107 gtk_widget_queue_draw (widget: priv->parent);
4108
4109out:
4110 if (priv->alloc_needed_on_child)
4111 gtk_widget_ensure_allocate (widget);
4112
4113 gtk_widget_pop_verify_invariants (widget);
4114}
4115
4116/**
4117 * gtk_widget_common_ancestor:
4118 * @widget_a: a `GtkWidget`
4119 * @widget_b: a `GtkWidget`
4120 *
4121 * Find the common ancestor of @widget_a and @widget_b that
4122 * is closest to the two widgets.
4123 *
4124 * Returns: (nullable): the closest common ancestor of @widget_a and
4125 * @widget_b or %NULL if @widget_a and @widget_b do not
4126 * share a common ancestor.
4127 */
4128GtkWidget *
4129gtk_widget_common_ancestor (GtkWidget *widget_a,
4130 GtkWidget *widget_b)
4131{
4132 GtkWidget *parent_a;
4133 GtkWidget *parent_b;
4134 int depth_a = 0;
4135 int depth_b = 0;
4136
4137 parent_a = widget_a;
4138 while (parent_a->priv->parent)
4139 {
4140 parent_a = parent_a->priv->parent;
4141 depth_a++;
4142 }
4143
4144 parent_b = widget_b;
4145 while (parent_b->priv->parent)
4146 {
4147 parent_b = parent_b->priv->parent;
4148 depth_b++;
4149 }
4150
4151 if (parent_a != parent_b)
4152 return NULL;
4153
4154 while (depth_a > depth_b)
4155 {
4156 widget_a = widget_a->priv->parent;
4157 depth_a--;
4158 }
4159
4160 while (depth_b > depth_a)
4161 {
4162 widget_b = widget_b->priv->parent;
4163 depth_b--;
4164 }
4165
4166 while (widget_a != widget_b)
4167 {
4168 widget_a = widget_a->priv->parent;
4169 widget_b = widget_b->priv->parent;
4170 }
4171
4172 return widget_a;
4173}
4174
4175/**
4176 * gtk_widget_translate_coordinates:
4177 * @src_widget: a `GtkWidget`
4178 * @dest_widget: a `GtkWidget`
4179 * @src_x: X position relative to @src_widget
4180 * @src_y: Y position relative to @src_widget
4181 * @dest_x: (out) (optional): location to store X position relative to @dest_widget
4182 * @dest_y: (out) (optional): location to store Y position relative to @dest_widget
4183 *
4184 * Translate coordinates relative to @src_widget’s allocation
4185 * to coordinates relative to @dest_widget’s allocations.
4186 *
4187 * In order to perform this operation, both widget must share
4188 * a common ancestor.
4189 *
4190 * Returns: %FALSE if @src_widget and @dest_widget have no common
4191 * ancestor. In this case, 0 is stored in *@dest_x and *@dest_y.
4192 * Otherwise %TRUE.
4193 */
4194gboolean
4195gtk_widget_translate_coordinates (GtkWidget *src_widget,
4196 GtkWidget *dest_widget,
4197 double src_x,
4198 double src_y,
4199 double *dest_x,
4200 double *dest_y)
4201{
4202 graphene_point_t p;
4203
4204 if (!gtk_widget_compute_point (widget: src_widget, target: dest_widget,
4205 point: &GRAPHENE_POINT_INIT (src_x, src_y),
4206 out_point: &p))
4207 return FALSE;
4208
4209 if (dest_x)
4210 *dest_x = p.x;
4211
4212 if (dest_y)
4213 *dest_y = p.y;
4214
4215 return TRUE;
4216}
4217
4218/**
4219 * gtk_widget_compute_point:
4220 * @widget: the `GtkWidget` to query
4221 * @target: the `GtkWidget` to transform into
4222 * @point: a point in @widget's coordinate system
4223 * @out_point: (out caller-allocates): Set to the corresponding coordinates in
4224 * @target's coordinate system
4225 *
4226 * Translates the given @point in @widget's coordinates to coordinates
4227 * relative to @target’s coordinate system.
4228 *
4229 * In order to perform this operation, both widgets must share a
4230 * common ancestor.
4231 *
4232 * Returns: %TRUE if the point could be determined, %FALSE on failure.
4233 * In this case, 0 is stored in @out_point.
4234 */
4235gboolean
4236gtk_widget_compute_point (GtkWidget *widget,
4237 GtkWidget *target,
4238 const graphene_point_t *point,
4239 graphene_point_t *out_point)
4240{
4241 graphene_matrix_t transform;
4242
4243 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
4244 g_return_val_if_fail (GTK_IS_WIDGET (target), FALSE);
4245
4246 if (!gtk_widget_compute_transform (widget, target, out_transform: &transform))
4247 {
4248 graphene_point_init (p: out_point, x: 0, y: 0);
4249 return FALSE;
4250 }
4251
4252 gsk_matrix_transform_point (m: &transform, p: point, res: out_point);
4253
4254 return TRUE;
4255}
4256
4257/**
4258 * gtk_widget_class_add_binding: (skip)
4259 * @widget_class: the class to add the binding to
4260 * @keyval: key value of binding to install
4261 * @mods: key modifier of binding to install
4262 * @callback: the callback to call upon activation
4263 * @format_string: (nullable): GVariant format string for arguments
4264 * or %NULL for no arguments
4265 * @...: arguments, as given by format string
4266 *
4267 * Creates a new shortcut for @widget_class that calls the given @callback
4268 * with arguments read according to @format_string.
4269 *
4270 * The arguments and format string must be provided in the same way as
4271 * with g_variant_new().
4272 *
4273 * This function is a convenience wrapper around
4274 * [method@Gtk.WidgetClass.add_shortcut] and must be called during class
4275 * initialization. It does not provide for user_data, if you need that,
4276 * you will have to use [method@GtkWidgetClass.add_shortcut] with a custom
4277 * shortcut.
4278 */
4279void
4280gtk_widget_class_add_binding (GtkWidgetClass *widget_class,
4281 guint keyval,
4282 GdkModifierType mods,
4283 GtkShortcutFunc callback,
4284 const char *format_string,
4285 ...)
4286{
4287 GtkShortcut *shortcut;
4288
4289 g_return_if_fail (GTK_IS_WIDGET_CLASS (widget_class));
4290
4291 shortcut = gtk_shortcut_new (trigger: gtk_keyval_trigger_new (keyval, modifiers: mods),
4292 action: gtk_callback_action_new (callback, NULL, NULL));
4293 if (format_string)
4294 {
4295 va_list args;
4296 va_start (args, format_string);
4297 gtk_shortcut_set_arguments (self: shortcut,
4298 args: g_variant_new_va (format_string, NULL, app: &args));
4299 va_end (args);
4300 }
4301
4302 gtk_widget_class_add_shortcut (widget_class, shortcut);
4303
4304 g_object_unref (object: shortcut);
4305}
4306
4307/**
4308 * gtk_widget_class_add_binding_signal: (skip)
4309 * @widget_class: the class to add the binding to
4310 * @keyval: key value of binding to install
4311 * @mods: key modifier of binding to install
4312 * @signal: the signal to execute
4313 * @format_string: (nullable): GVariant format string for arguments
4314 * or %NULL for no arguments
4315 * @...: arguments, as given by format string
4316 *
4317 * Creates a new shortcut for @widget_class that emits the given action
4318 * @signal with arguments read according to @format_string.
4319 *
4320 * The arguments and format string must be provided in the same way as
4321 * with g_variant_new().
4322 *
4323 * This function is a convenience wrapper around
4324 * [method@Gtk.WidgetClass.add_shortcut] and must be called during class
4325 * initialization.
4326 */
4327void
4328gtk_widget_class_add_binding_signal (GtkWidgetClass *widget_class,
4329 guint keyval,
4330 GdkModifierType mods,
4331 const char *signal,
4332 const char *format_string,
4333 ...)
4334{
4335 GtkShortcut *shortcut;
4336
4337 g_return_if_fail (GTK_IS_WIDGET_CLASS (widget_class));
4338 g_return_if_fail (g_signal_lookup (signal, G_TYPE_FROM_CLASS (widget_class)));
4339 /* XXX: validate variant format for signal */
4340
4341 shortcut = gtk_shortcut_new (trigger: gtk_keyval_trigger_new (keyval, modifiers: mods),
4342 action: gtk_signal_action_new (signal_name: signal));
4343 if (format_string)
4344 {
4345 va_list args;
4346 va_start (args, format_string);
4347 gtk_shortcut_set_arguments (self: shortcut,
4348 args: g_variant_new_va (format_string, NULL, app: &args));
4349 va_end (args);
4350 }
4351
4352 gtk_widget_class_add_shortcut (widget_class, shortcut);
4353
4354 g_object_unref (object: shortcut);
4355}
4356
4357/**
4358 * gtk_widget_class_add_binding_action: (skip)
4359 * @widget_class: the class to add the binding to
4360 * @keyval: key value of binding to install
4361 * @mods: key modifier of binding to install
4362 * @action_name: the action to activate
4363 * @format_string: (nullable): GVariant format string for arguments
4364 * or %NULL for no arguments
4365 * @...: arguments, as given by format string
4366 *
4367 * Creates a new shortcut for @widget_class that activates the given
4368 * @action_name with arguments read according to @format_string.
4369 *
4370 * The arguments and format string must be provided in the same way as
4371 * with g_variant_new().
4372 *
4373 * This function is a convenience wrapper around
4374 * [method@Gtk.WidgetClass.add_shortcut] and must be called during class
4375 * initialization.
4376 */
4377void
4378gtk_widget_class_add_binding_action (GtkWidgetClass *widget_class,
4379 guint keyval,
4380 GdkModifierType mods,
4381 const char *action_name,
4382 const char *format_string,
4383 ...)
4384{
4385 GtkShortcut *shortcut;
4386
4387 g_return_if_fail (GTK_IS_WIDGET_CLASS (widget_class));
4388 /* XXX: validate variant format for action */
4389
4390 shortcut = gtk_shortcut_new (trigger: gtk_keyval_trigger_new (keyval, modifiers: mods),
4391 action: gtk_named_action_new (name: action_name));
4392 if (format_string)
4393 {
4394 va_list args;
4395 va_start (args, format_string);
4396 gtk_shortcut_set_arguments (self: shortcut,
4397 args: g_variant_new_va (format_string, NULL, app: &args));
4398 va_end (args);
4399 }
4400
4401 gtk_widget_class_add_shortcut (widget_class, shortcut);
4402
4403 g_object_unref (object: shortcut);
4404}
4405
4406/**
4407 * gtk_widget_class_add_shortcut:
4408 * @widget_class: the class to add the shortcut to
4409 * @shortcut: (transfer none): the `GtkShortcut` to add
4410 *
4411 * Installs a shortcut in @widget_class.
4412 *
4413 * Every instance created for @widget_class or its subclasses will
4414 * inherit this shortcut and trigger it.
4415 *
4416 * Shortcuts added this way will be triggered in the %GTK_PHASE_BUBBLE
4417 * phase, which means they may also trigger if child widgets have focus.
4418 *
4419 * This function must only be used in class initialization functions
4420 * otherwise it is not guaranteed that the shortcut will be installed.
4421 */
4422void
4423gtk_widget_class_add_shortcut (GtkWidgetClass *widget_class,
4424 GtkShortcut *shortcut)
4425{
4426 GtkWidgetClassPrivate *priv;
4427
4428 g_return_if_fail (GTK_IS_WIDGET_CLASS (widget_class));
4429 g_return_if_fail (GTK_IS_SHORTCUT (shortcut));
4430
4431 priv = widget_class->priv;
4432
4433 g_list_store_append (store: priv->shortcuts, item: shortcut);
4434}
4435
4436/**
4437 * gtk_widget_mnemonic_activate:
4438 * @widget: a `GtkWidget`
4439 * @group_cycling: %TRUE if there are other widgets with the same mnemonic
4440 *
4441 * Emits the ::mnemonic-activate signal.
4442 *
4443 * See [signal@Gtk.Widget::mnemonic-activate].
4444 *
4445 * Returns: %TRUE if the signal has been handled
4446 */
4447gboolean
4448gtk_widget_mnemonic_activate (GtkWidget *widget,
4449 gboolean group_cycling)
4450{
4451 gboolean handled;
4452
4453 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
4454
4455 group_cycling = group_cycling != FALSE;
4456 if (!gtk_widget_is_sensitive (widget))
4457 handled = TRUE;
4458 else
4459 g_signal_emit (instance: widget,
4460 signal_id: widget_signals[MNEMONIC_ACTIVATE],
4461 detail: 0,
4462 group_cycling,
4463 &handled);
4464 return handled;
4465}
4466
4467/*< private >
4468 * gtk_widget_can_activate:
4469 * @self: a `GtkWidget`
4470 *
4471 * Checks whether a `GtkWidget` can be activated.
4472 *
4473 * To activate a widget, use [method@Gtk.Widget.activate].
4474 */
4475gboolean
4476gtk_widget_can_activate (GtkWidget *self)
4477{
4478 g_return_val_if_fail (GTK_IS_WIDGET (self), FALSE);
4479
4480 GtkWidgetClass *widget_class = GTK_WIDGET_GET_CLASS (self);
4481
4482 if (widget_class->priv->activate_signal != 0)
4483 return TRUE;
4484
4485 return FALSE;
4486}
4487
4488static gboolean
4489get_effective_can_focus (GtkWidget *widget)
4490{
4491 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
4492
4493 if (!priv->can_focus)
4494 return FALSE;
4495
4496 if (priv->parent)
4497 return get_effective_can_focus (widget: priv->parent);
4498
4499 return TRUE;
4500}
4501
4502static gboolean
4503gtk_widget_real_mnemonic_activate (GtkWidget *widget,
4504 gboolean group_cycling)
4505{
4506 if (!group_cycling && gtk_widget_can_activate (self: widget))
4507 gtk_widget_activate (widget);
4508 else if (get_effective_can_focus (widget))
4509 return gtk_widget_grab_focus (widget);
4510 else
4511 {
4512 g_warning ("widget '%s' isn't suitable for mnemonic activation",
4513 G_OBJECT_TYPE_NAME (widget));
4514 gtk_widget_error_bell (widget);
4515 }
4516 return TRUE;
4517}
4518
4519#define WIDGET_REALIZED_FOR_EVENT(widget, event) \
4520 (gdk_event_get_event_type (event) == GDK_FOCUS_CHANGE || _gtk_widget_get_realized (widget))
4521
4522gboolean
4523gtk_widget_run_controllers (GtkWidget *widget,
4524 GdkEvent *event,
4525 GtkWidget *target,
4526 double x,
4527 double y,
4528 GtkPropagationPhase phase)
4529{
4530 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
4531 GtkEventController *controller;
4532 gboolean handled = FALSE;
4533 GList *l;
4534
4535 g_object_ref (widget);
4536
4537 l = priv->event_controllers;
4538 while (l != NULL)
4539 {
4540 GList *next = l->next;
4541
4542 if (!WIDGET_REALIZED_FOR_EVENT (widget, event))
4543 break;
4544
4545 controller = l->data;
4546
4547 if (controller == NULL)
4548 {
4549 priv->event_controllers = g_list_delete_link (list: priv->event_controllers, link_: l);
4550 }
4551 else
4552 {
4553 GtkPropagationPhase controller_phase;
4554
4555 controller_phase = gtk_event_controller_get_propagation_phase (controller);
4556
4557 if (controller_phase == phase)
4558 {
4559 gboolean this_handled;
4560 gboolean is_gesture;
4561
4562 is_gesture = GTK_IS_GESTURE (controller);
4563 this_handled = gtk_event_controller_handle_event (controller, event, target, x, y);
4564
4565#ifdef G_ENABLE_DEBUG
4566 if (GTK_DEBUG_CHECK (KEYBINDINGS))
4567 {
4568 GdkEventType type = gdk_event_get_event_type (event);
4569 if (this_handled &&
4570 (type == GDK_KEY_PRESS || type == GDK_KEY_RELEASE))
4571 {
4572 g_message ("key %s (keyval %d) handled at widget %s by controller %s",
4573 type == GDK_KEY_PRESS ? "press" : "release",
4574 gdk_key_event_get_keyval (event),
4575 G_OBJECT_TYPE_NAME (widget),
4576 gtk_event_controller_get_name (controller));
4577 }
4578 }
4579#endif
4580
4581 handled |= this_handled;
4582
4583 /* Non-gesture controllers are basically unique entities not meant
4584 * to collaborate with anything else. Break early if any such event
4585 * controller handled the event.
4586 */
4587 if (this_handled && !is_gesture)
4588 break;
4589 }
4590 }
4591
4592 l = next;
4593 }
4594
4595 g_object_unref (object: widget);
4596
4597 return handled;
4598}
4599
4600void
4601gtk_widget_handle_crossing (GtkWidget *widget,
4602 const GtkCrossingData *crossing,
4603 double x,
4604 double y)
4605{
4606 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
4607 GList *l;
4608
4609 g_object_ref (widget);
4610
4611 if (crossing->old_target)
4612 g_object_ref (crossing->old_target);
4613 if (crossing->new_target)
4614 g_object_ref (crossing->new_target);
4615 if (crossing->old_descendent)
4616 g_object_ref (crossing->old_descendent);
4617 if (crossing->new_descendent)
4618 g_object_ref (crossing->new_descendent);
4619
4620 for (l = priv->event_controllers; l; l = l->next)
4621 {
4622 GtkEventController *controller = l->data;
4623 gtk_event_controller_handle_crossing (controller, crossing, x, y);
4624 }
4625
4626 if (crossing->old_target)
4627 g_object_unref (object: crossing->old_target);
4628 if (crossing->new_target)
4629 g_object_unref (object: crossing->new_target);
4630 if (crossing->old_descendent)
4631 g_object_unref (object: crossing->old_descendent);
4632 if (crossing->new_descendent)
4633 g_object_unref (object: crossing->new_descendent);
4634
4635 g_object_unref (object: widget);
4636}
4637
4638static gboolean
4639event_surface_is_still_viewable (GdkEvent *event)
4640{
4641 /* Check that we think the event's window is viewable before
4642 * delivering the event, to prevent surprises. We do this here
4643 * at the last moment, since the event may have been queued
4644 * up behind other events, held over a recursive main loop, etc.
4645 */
4646 switch ((guint) gdk_event_get_event_type (event))
4647 {
4648 case GDK_MOTION_NOTIFY:
4649 case GDK_BUTTON_PRESS:
4650 case GDK_KEY_PRESS:
4651 case GDK_ENTER_NOTIFY:
4652 case GDK_PROXIMITY_IN:
4653 case GDK_SCROLL:
4654 return gdk_surface_get_mapped (surface: gdk_event_get_surface (event));
4655
4656#if 0
4657 /* The following events are the second half of paired events;
4658 * we always deliver them to deal with widgets that clean up
4659 * on the second half.
4660 */
4661 case GDK_BUTTON_RELEASE:
4662 case GDK_KEY_RELEASE:
4663 case GDK_LEAVE_NOTIFY:
4664 case GDK_PROXIMITY_OUT:
4665#endif
4666
4667 default:
4668 /* Remaining events would make sense on a not-viewable window,
4669 * or don't have an associated window.
4670 */
4671 return TRUE;
4672 }
4673}
4674
4675static gboolean
4676translate_event_coordinates (GdkEvent *event,
4677 double *x,
4678 double *y,
4679 GtkWidget *widget)
4680{
4681 GtkWidget *event_widget;
4682 graphene_point_t p;
4683 double event_x, event_y;
4684 GtkNative *native;
4685 double nx, ny;
4686
4687 *x = *y = 0;
4688
4689 if (!gdk_event_get_position (event, x: &event_x, y: &event_y))
4690 return FALSE;
4691
4692 event_widget = gtk_get_event_widget (event);
4693 native = gtk_widget_get_native (widget: event_widget);
4694 gtk_native_get_surface_transform (self: native, x: &nx, y: &ny);
4695 event_x -= nx;
4696 event_y -= ny;
4697
4698 if (!gtk_widget_compute_point (widget: event_widget,
4699 target: widget,
4700 point: &GRAPHENE_POINT_INIT (event_x, event_y),
4701 out_point: &p))
4702 return FALSE;
4703
4704 *x = p.x;
4705 *y = p.y;
4706
4707 return TRUE;
4708}
4709
4710gboolean
4711_gtk_widget_captured_event (GtkWidget *widget,
4712 GdkEvent *event,
4713 GtkWidget *target)
4714{
4715 gboolean return_val = FALSE;
4716 double x, y;
4717
4718 g_return_val_if_fail (GTK_IS_WIDGET (widget), TRUE);
4719 g_return_val_if_fail (WIDGET_REALIZED_FOR_EVENT (widget, event), TRUE);
4720
4721 if (!event_surface_is_still_viewable (event))
4722 return TRUE;
4723
4724 translate_event_coordinates (event, x: &x, y: &y, widget);
4725
4726 return_val = gtk_widget_run_controllers (widget, event, target, x, y, phase: GTK_PHASE_CAPTURE);
4727 return_val |= !WIDGET_REALIZED_FOR_EVENT (widget, event);
4728
4729 return return_val;
4730}
4731
4732gboolean
4733gtk_widget_event (GtkWidget *widget,
4734 GdkEvent *event,
4735 GtkWidget *target)
4736{
4737 gboolean return_val = FALSE;
4738 double x, y;
4739
4740 /* We check only once for is-still-visible; if someone
4741 * hides the window in one of the signals on the widget,
4742 * they are responsible for returning TRUE to terminate
4743 * handling.
4744 */
4745 if (!event_surface_is_still_viewable (event))
4746 return TRUE;
4747
4748 if (!_gtk_widget_get_mapped (widget))
4749 return FALSE;
4750
4751 translate_event_coordinates (event, x: &x, y: &y, widget);
4752
4753 if (widget == target)
4754 return_val |= gtk_widget_run_controllers (widget, event, target, x, y, phase: GTK_PHASE_TARGET);
4755
4756 if (return_val == FALSE)
4757 return_val |= gtk_widget_run_controllers (widget, event, target, x, y, phase: GTK_PHASE_BUBBLE);
4758
4759 return return_val;
4760}
4761
4762/**
4763 * gtk_widget_class_get_activate_signal:
4764 * @widget_class: a `GtkWidgetClass`
4765 *
4766 * Retrieves the signal id for the activation signal.
4767 *
4768 * the activation signal is set using
4769 * [method@Gtk.WidgetClass.set_activate_signal].
4770 *
4771 * Returns: a signal id, or 0 if the widget class does not
4772 * specify an activation signal
4773 */
4774guint
4775gtk_widget_class_get_activate_signal (GtkWidgetClass *widget_class)
4776{
4777 g_return_val_if_fail (GTK_IS_WIDGET_CLASS (widget_class), 0);
4778
4779 return widget_class->priv->activate_signal;
4780}
4781
4782/**
4783 * gtk_widget_class_set_activate_signal:
4784 * @widget_class: a `GtkWidgetClass`
4785 * @signal_id: the id for the activate signal
4786 *
4787 * Sets the `GtkWidgetClass.activate_signal` field with the
4788 * given @signal_id.
4789 *
4790 * The signal will be emitted when calling [method@Gtk.Widget.activate].
4791 *
4792 * The @signal_id must have been registered with `g_signal_new()`
4793 * or g_signal_newv() before calling this function.
4794 */
4795void
4796gtk_widget_class_set_activate_signal (GtkWidgetClass *widget_class,
4797 guint signal_id)
4798{
4799 g_return_if_fail (GTK_IS_WIDGET_CLASS (widget_class));
4800 g_return_if_fail (signal_id != 0);
4801
4802 widget_class->priv->activate_signal = signal_id;
4803}
4804
4805/**
4806 * gtk_widget_class_set_activate_signal_from_name:
4807 * @widget_class: a `GtkWidgetClass`
4808 * @signal_name: the name of the activate signal of @widget_type
4809 *
4810 * Sets the `GtkWidgetClass.activate_signal` field with the signal id for
4811 * the given @signal_name.
4812 *
4813 * The signal will be emitted when calling [method@Gtk.Widget.activate].
4814 *
4815 * The @signal_name of @widget_type must have been registered with
4816 * g_signal_new() or g_signal_newv() before calling this function.
4817 */
4818void
4819gtk_widget_class_set_activate_signal_from_name (GtkWidgetClass *widget_class,
4820 const char *signal_name)
4821{
4822 guint signal_id;
4823
4824 g_return_if_fail (GTK_IS_WIDGET_CLASS (widget_class));
4825 g_return_if_fail (signal_name != NULL);
4826
4827 signal_id = g_signal_lookup (name: signal_name, G_TYPE_FROM_CLASS (widget_class));
4828 if (signal_id == 0)
4829 {
4830 g_critical ("Widget type “%s” does not have a “%s” signal",
4831 G_OBJECT_CLASS_NAME (widget_class),
4832 signal_name);
4833 return;
4834 }
4835
4836 widget_class->priv->activate_signal = signal_id;
4837}
4838
4839/**
4840 * gtk_widget_activate:
4841 * @widget: a `GtkWidget` that’s activatable
4842 *
4843 * For widgets that can be “activated” (buttons, menu items, etc.),
4844 * this function activates them.
4845 *
4846 * The activation will emit the signal set using
4847 * [method@Gtk.WidgetClass.set_activate_signal] during class initialization.
4848 *
4849 * Activation is what happens when you press <kbd>Enter</kbd>
4850 * on a widget during key navigation.
4851 *
4852 * If you wish to handle the activation keybinding yourself, it is
4853 * recommended to use [method@Gtk.WidgetClass.add_shortcut] with an action
4854 * created with [ctor@Gtk.SignalAction.new].
4855 *
4856 * If @widget isn't activatable, the function returns %FALSE.
4857 *
4858 * Returns: %TRUE if the widget was activatable
4859 */
4860gboolean
4861gtk_widget_activate (GtkWidget *widget)
4862{
4863 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
4864
4865 if (gtk_widget_can_activate (self: widget))
4866 {
4867 GtkWidgetClass *widget_class = GTK_WIDGET_GET_CLASS (widget);
4868 /* FIXME: we should eventually check the signals signature here */
4869 g_signal_emit (instance: widget, signal_id: widget_class->priv->activate_signal, detail: 0);
4870
4871 return TRUE;
4872 }
4873 else
4874 return FALSE;
4875}
4876
4877/**
4878 * gtk_widget_grab_focus:
4879 * @widget: a `GtkWidget`
4880 *
4881 * Causes @widget to have the keyboard focus for the `GtkWindow` it's inside.
4882 *
4883 * If @widget is not focusable, or its [vfunc@Gtk.Widget.grab_focus]
4884 * implementation cannot transfer the focus to a descendant of @widget
4885 * that is focusable, it will not take focus and %FALSE will be returned.
4886 *
4887 * Calling [method@Gtk.Widget.grab_focus] on an already focused widget
4888 * is allowed, should not have an effect, and return %TRUE.
4889 *
4890 * Returns: %TRUE if focus is now inside @widget.
4891 */
4892gboolean
4893gtk_widget_grab_focus (GtkWidget *widget)
4894{
4895 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
4896
4897 if (!gtk_widget_is_sensitive (widget) ||
4898 !get_effective_can_focus (widget) ||
4899 widget->priv->root == NULL)
4900 return FALSE;
4901
4902 return GTK_WIDGET_GET_CLASS (widget)->grab_focus (widget);
4903}
4904
4905gboolean
4906gtk_widget_grab_focus_self (GtkWidget *widget)
4907{
4908 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
4909
4910 if (!priv->focusable)
4911 return FALSE;
4912
4913 gtk_root_set_focus (self: priv->root, focus: widget);
4914
4915 return TRUE;
4916}
4917
4918gboolean
4919gtk_widget_grab_focus_child (GtkWidget *widget)
4920{
4921 GtkWidget *child;
4922
4923 for (child = _gtk_widget_get_first_child (widget);
4924 child != NULL;
4925 child = _gtk_widget_get_next_sibling (widget: child))
4926 {
4927 if (gtk_widget_grab_focus (widget: child))
4928 return TRUE;
4929 }
4930
4931 return FALSE;
4932}
4933
4934gboolean
4935gtk_widget_query_tooltip (GtkWidget *widget,
4936 int x,
4937 int y,
4938 gboolean keyboard_mode,
4939 GtkTooltip *tooltip)
4940{
4941 gboolean retval = FALSE;
4942
4943 g_signal_emit (instance: widget,
4944 signal_id: widget_signals[QUERY_TOOLTIP],
4945 detail: 0,
4946 x, y,
4947 keyboard_mode,
4948 tooltip,
4949 &retval);
4950
4951 return retval;
4952}
4953
4954static void
4955gtk_widget_real_css_changed (GtkWidget *widget,
4956 GtkCssStyleChange *change)
4957{
4958 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
4959
4960 if (change)
4961 {
4962 const gboolean has_text = gtk_widget_peek_pango_context (widget) != NULL;
4963
4964 if (has_text && gtk_css_style_change_affects (change, GTK_CSS_AFFECTS_TEXT))
4965 gtk_widget_update_default_pango_context (widget);
4966
4967 if (priv->root)
4968 {
4969 if (gtk_css_style_change_affects (change, affects: GTK_CSS_AFFECTS_SIZE) ||
4970 (has_text && gtk_css_style_change_affects (change, affects: GTK_CSS_AFFECTS_TEXT_SIZE)))
4971 {
4972 gtk_widget_queue_resize (widget);
4973 }
4974 else if (gtk_css_style_change_affects (change, affects: GTK_CSS_AFFECTS_TRANSFORM) &&
4975 priv->parent)
4976 {
4977 gtk_widget_queue_allocate (widget: priv->parent);
4978 }
4979
4980 if (gtk_css_style_change_affects (change, GTK_CSS_AFFECTS_REDRAW) ||
4981 (has_text && gtk_css_style_change_affects (change, affects: GTK_CSS_AFFECTS_TEXT_CONTENT)))
4982 {
4983 gtk_widget_queue_draw (widget);
4984 }
4985 }
4986 }
4987 else
4988 {
4989 gtk_widget_update_default_pango_context (widget);
4990
4991 if (priv->root)
4992 gtk_widget_queue_resize (widget);
4993 }
4994}
4995
4996static void
4997gtk_widget_real_system_setting_changed (GtkWidget *widget,
4998 GtkSystemSetting setting)
4999{
5000 GtkWidget *child;
5001
5002 if (setting == GTK_SYSTEM_SETTING_DPI ||
5003 setting == GTK_SYSTEM_SETTING_FONT_NAME ||
5004 setting == GTK_SYSTEM_SETTING_FONT_CONFIG)
5005 {
5006 gtk_widget_update_default_pango_context (widget);
5007 if (gtk_widget_peek_pango_context (widget))
5008 gtk_widget_queue_resize (widget);
5009 }
5010
5011 for (child = _gtk_widget_get_first_child (widget);
5012 child != NULL;
5013 child = _gtk_widget_get_next_sibling (widget: child))
5014 {
5015 gtk_widget_system_setting_changed (widget: child, setting);
5016 }
5017}
5018
5019static gboolean
5020direction_is_forward (GtkDirectionType direction)
5021{
5022 switch (direction)
5023 {
5024 case GTK_DIR_TAB_FORWARD:
5025 case GTK_DIR_RIGHT:
5026 case GTK_DIR_DOWN:
5027 return TRUE;
5028 case GTK_DIR_TAB_BACKWARD:
5029 case GTK_DIR_LEFT:
5030 case GTK_DIR_UP:
5031 return FALSE;
5032 default:
5033 g_assert_not_reached ();
5034 }
5035}
5036
5037static gboolean
5038gtk_widget_real_focus (GtkWidget *widget,
5039 GtkDirectionType direction)
5040{
5041 GtkWidget *focus;
5042
5043 /* For focusable widgets, we want to focus the widget
5044 * before its children. We differentiate 3 cases:
5045 * 1) focus is currently on widget
5046 * 2) focus is on some child
5047 * 3) focus is outside
5048 */
5049
5050 if (gtk_widget_is_focus (widget))
5051 {
5052 if (direction_is_forward (direction) &&
5053 gtk_widget_focus_move (widget, direction))
5054 return TRUE;
5055
5056 return FALSE;
5057 }
5058
5059 focus = gtk_window_get_focus (GTK_WINDOW (gtk_widget_get_root (widget)));
5060
5061 if (focus && gtk_widget_is_ancestor (widget: focus, ancestor: widget))
5062 {
5063 if (gtk_widget_focus_move (widget, direction))
5064 return TRUE;
5065
5066 if (direction_is_forward (direction))
5067 return FALSE;
5068 else
5069 return gtk_widget_grab_focus (widget);
5070 }
5071
5072 if (!direction_is_forward (direction))
5073 {
5074 if (gtk_widget_focus_move (widget, direction))
5075 return TRUE;
5076
5077 return gtk_widget_grab_focus (widget);
5078 }
5079 else
5080 {
5081 if (gtk_widget_grab_focus (widget))
5082 return TRUE;
5083
5084 return gtk_widget_focus_move (widget, direction);
5085 }
5086}
5087
5088gboolean
5089gtk_widget_focus_self (GtkWidget *widget,
5090 GtkDirectionType direction)
5091{
5092 if (!gtk_widget_is_focus (widget))
5093 {
5094 gtk_widget_grab_focus (widget);
5095 return TRUE;
5096 }
5097 return FALSE;
5098}
5099
5100gboolean
5101gtk_widget_focus_child (GtkWidget *widget,
5102 GtkDirectionType direction)
5103{
5104 return gtk_widget_focus_move (widget, direction);
5105}
5106
5107static void
5108gtk_widget_real_move_focus (GtkWidget *widget,
5109 GtkDirectionType direction)
5110{
5111 GtkRoot *root;
5112
5113 root = _gtk_widget_get_root (widget);
5114 if (widget != GTK_WIDGET (root))
5115 g_signal_emit (instance: root, signal_id: widget_signals[MOVE_FOCUS], detail: 0, direction);
5116}
5117
5118static gboolean
5119gtk_widget_real_keynav_failed (GtkWidget *widget,
5120 GtkDirectionType direction)
5121{
5122 switch (direction)
5123 {
5124 case GTK_DIR_TAB_FORWARD:
5125 case GTK_DIR_TAB_BACKWARD:
5126 return FALSE;
5127
5128 case GTK_DIR_UP:
5129 case GTK_DIR_DOWN:
5130 case GTK_DIR_LEFT:
5131 case GTK_DIR_RIGHT:
5132 default:
5133 break;
5134 }
5135
5136 gtk_widget_error_bell (widget);
5137
5138 return TRUE;
5139}
5140
5141/**
5142 * gtk_widget_set_can_focus: (attributes org.gtk.Method.set_property=can-focus)
5143 * @widget: a `GtkWidget`
5144 * @can_focus: whether or not the input focus can enter
5145 * the widget or any of its children
5146 *
5147 * Specifies whether the input focus can enter the widget
5148 * or any of its children.
5149 *
5150 * Applications should set @can_focus to %FALSE to mark a
5151 * widget as for pointer/touch use only.
5152 *
5153 * Note that having @can_focus be %TRUE is only one of the
5154 * necessary conditions for being focusable. A widget must
5155 * also be sensitive and focusable and not have an ancestor
5156 * that is marked as not can-focus in order to receive input
5157 * focus.
5158 *
5159 * See [method@Gtk.Widget.grab_focus] for actually setting
5160 * the input focus on a widget.
5161 */
5162void
5163gtk_widget_set_can_focus (GtkWidget *widget,
5164 gboolean can_focus)
5165{
5166 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
5167
5168 g_return_if_fail (GTK_IS_WIDGET (widget));
5169
5170 if (priv->can_focus != can_focus)
5171 {
5172 priv->can_focus = can_focus;
5173
5174 gtk_widget_queue_resize (widget);
5175 g_object_notify_by_pspec (G_OBJECT (widget), pspec: widget_props[PROP_CAN_FOCUS]);
5176 }
5177}
5178
5179/**
5180 * gtk_widget_get_can_focus: (attributes org.gtk.Method.get_property=can-focus)
5181 * @widget: a `GtkWidget`
5182 *
5183 * Determines whether the input focus can enter @widget or any
5184 * of its children.
5185 *
5186 * See [method@Gtk.Widget.set_focusable].
5187 *
5188 * Returns: %TRUE if the input focus can enter @widget, %FALSE otherwise
5189 */
5190gboolean
5191gtk_widget_get_can_focus (GtkWidget *widget)
5192{
5193 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
5194
5195 g_return_val_if_fail (GTK_IS_WIDGET (widget), TRUE);
5196
5197 return priv->can_focus;
5198}
5199
5200/**
5201 * gtk_widget_set_focusable: (attributes org.gtk.Method.set_property=focusable)
5202 * @widget: a `GtkWidget`
5203 * @focusable: whether or not @widget can own the input focus
5204 *
5205 * Specifies whether @widget can own the input focus.
5206 *
5207 * Widget implementations should set @focusable to %TRUE in
5208 * their init() function if they want to receive keyboard input.
5209 *
5210 * Note that having @focusable be %TRUE is only one of the
5211 * necessary conditions for being focusable. A widget must
5212 * also be sensitive and can-focus and not have an ancestor
5213 * that is marked as not can-focus in order to receive input
5214 * focus.
5215 *
5216 * See [method@Gtk.Widget.grab_focus] for actually setting
5217 * the input focus on a widget.
5218 */
5219void
5220gtk_widget_set_focusable (GtkWidget *widget,
5221 gboolean focusable)
5222{
5223 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
5224
5225 g_return_if_fail (GTK_IS_WIDGET (widget));
5226
5227 if (priv->focusable == focusable)
5228 return;
5229
5230 priv->focusable = focusable;
5231
5232 gtk_widget_queue_resize (widget);
5233
5234 gtk_accessible_platform_changed (self: GTK_ACCESSIBLE (ptr: widget), change: GTK_ACCESSIBLE_PLATFORM_CHANGE_FOCUSABLE);
5235
5236 g_object_notify_by_pspec (G_OBJECT (widget), pspec: widget_props[PROP_FOCUSABLE]);
5237}
5238
5239/**
5240 * gtk_widget_get_focusable: (attributes org.gtk.Method.get_property=focusable)
5241 * @widget: a `GtkWidget`
5242 *
5243 * Determines whether @widget can own the input focus.
5244 *
5245 * See [method@Gtk.Widget.set_focusable].
5246 *
5247 * Returns: %TRUE if @widget can own the input focus, %FALSE otherwise
5248 */
5249gboolean
5250gtk_widget_get_focusable (GtkWidget *widget)
5251{
5252 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
5253
5254 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
5255
5256 return priv->focusable;
5257}
5258
5259/**
5260 * gtk_widget_has_focus: (attributes org.gtk.Method.get_property=has-focus)
5261 * @widget: a `GtkWidget`
5262 *
5263 * Determines if the widget has the global input focus.
5264 *
5265 * See [method@Gtk.Widget.is_focus] for the difference between
5266 * having the global input focus, and only having the focus
5267 * within a toplevel.
5268 *
5269 * Returns: %TRUE if the widget has the global input focus.
5270 */
5271gboolean
5272gtk_widget_has_focus (GtkWidget *widget)
5273{
5274 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
5275
5276 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
5277
5278 return priv->has_focus;
5279}
5280
5281/**
5282 * gtk_widget_has_visible_focus:
5283 * @widget: a `GtkWidget`
5284 *
5285 * Determines if the widget should show a visible indication that
5286 * it has the global input focus.
5287 *
5288 * This is a convenience function that takes into account whether
5289 * focus indication should currently be shown in the toplevel window
5290 * of @widget. See [method@Gtk.Window.get_focus_visible] for more
5291 * information about focus indication.
5292 *
5293 * To find out if the widget has the global input focus, use
5294 * [method@Gtk.Widget.has_focus].
5295 *
5296 * Returns: %TRUE if the widget should display a “focus rectangle”
5297 */
5298gboolean
5299gtk_widget_has_visible_focus (GtkWidget *widget)
5300{
5301 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
5302 gboolean draw_focus;
5303
5304 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
5305
5306 if (priv->has_focus)
5307 {
5308 GtkRoot *root = _gtk_widget_get_root (widget);
5309
5310 if (GTK_IS_WINDOW (root))
5311 draw_focus = gtk_window_get_focus_visible (GTK_WINDOW (root));
5312 else
5313 draw_focus = TRUE;
5314 }
5315 else
5316 draw_focus = FALSE;
5317
5318 return draw_focus;
5319}
5320
5321/**
5322 * gtk_widget_is_focus:
5323 * @widget: a `GtkWidget`
5324 *
5325 * Determines if the widget is the focus widget within its
5326 * toplevel.
5327 *
5328 * This does not mean that the [property@Gtk.Widget:has-focus]
5329 * property is necessarily set; [property@Gtk.Widget:has-focus]
5330 * will only be set if the toplevel widget additionally has the
5331 * global input focus.
5332 *
5333 * Returns: %TRUE if the widget is the focus widget.
5334 */
5335gboolean
5336gtk_widget_is_focus (GtkWidget *widget)
5337{
5338 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
5339
5340 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
5341
5342 if (priv->root)
5343 return widget == gtk_root_get_focus (self: priv->root);
5344
5345 return FALSE;
5346}
5347
5348/**
5349 * gtk_widget_set_focus_on_click: (attributes org.gtk.Method.set_property=focus-on-click)
5350 * @widget: a `GtkWidget`
5351 * @focus_on_click: whether the widget should grab focus when clicked
5352 * with the mouse
5353 *
5354 * Sets whether the widget should grab focus when it is clicked
5355 * with the mouse.
5356 *
5357 * Making mouse clicks not grab focus is useful in places like
5358 * toolbars where you don’t want the keyboard focus removed from
5359 * the main area of the application.
5360 */
5361void
5362gtk_widget_set_focus_on_click (GtkWidget *widget,
5363 gboolean focus_on_click)
5364{
5365 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
5366
5367 g_return_if_fail (GTK_IS_WIDGET (widget));
5368
5369 focus_on_click = focus_on_click != FALSE;
5370
5371 if (priv->focus_on_click != focus_on_click)
5372 {
5373 priv->focus_on_click = focus_on_click;
5374
5375 g_object_notify_by_pspec (G_OBJECT (widget), pspec: widget_props[PROP_FOCUS_ON_CLICK]);
5376 }
5377}
5378
5379/**
5380 * gtk_widget_get_focus_on_click: (attributes org.gtk.Method.get_property=focus-on-click)
5381 * @widget: a `GtkWidget`
5382 *
5383 * Returns whether the widget should grab focus when it is clicked
5384 * with the mouse.
5385 *
5386 * See [method@Gtk.Widget.set_focus_on_click].
5387 *
5388 * Returns: %TRUE if the widget should grab focus when it is
5389 * clicked with the mouse
5390 */
5391gboolean
5392gtk_widget_get_focus_on_click (GtkWidget *widget)
5393{
5394 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
5395
5396 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
5397
5398 return priv->focus_on_click;
5399}
5400
5401/**
5402 * gtk_widget_has_default: (attributes org.gtk.Method.get_property=has-default)
5403 * @widget: a `GtkWidget`
5404 *
5405 * Determines whether @widget is the current default widget
5406 * within its toplevel.
5407 *
5408 * Returns: %TRUE if @widget is the current default widget
5409 * within its toplevel, %FALSE otherwise
5410 */
5411gboolean
5412gtk_widget_has_default (GtkWidget *widget)
5413{
5414 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
5415
5416 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
5417
5418 return priv->has_default;
5419}
5420
5421void
5422_gtk_widget_set_has_default (GtkWidget *widget,
5423 gboolean has_default)
5424{
5425 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
5426
5427 priv->has_default = has_default;
5428
5429 if (has_default)
5430 gtk_widget_add_css_class (widget, css_class: "default");
5431 else
5432 gtk_widget_remove_css_class (widget, css_class: "default");
5433}
5434
5435/**
5436 * gtk_widget_set_receives_default: (attributes org.gtk.Method.set_property=receives-default)
5437 * @widget: a `GtkWidget`
5438 * @receives_default: whether or not @widget can be a default widget.
5439 *
5440 * Specifies whether @widget will be treated as the default
5441 * widget within its toplevel when it has the focus, even if
5442 * another widget is the default.
5443 */
5444void
5445gtk_widget_set_receives_default (GtkWidget *widget,
5446 gboolean receives_default)
5447{
5448 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
5449
5450 g_return_if_fail (GTK_IS_WIDGET (widget));
5451
5452 if (priv->receives_default != receives_default)
5453 {
5454 priv->receives_default = receives_default;
5455
5456 g_object_notify_by_pspec (G_OBJECT (widget), pspec: widget_props[PROP_RECEIVES_DEFAULT]);
5457 }
5458}
5459
5460/**
5461 * gtk_widget_get_receives_default: (attributes org.gtk.Method.get_property=receives-default)
5462 * @widget: a `GtkWidget`
5463 *
5464 * Determines whether @widget is always treated as the default widget
5465 * within its toplevel when it has the focus, even if another widget
5466 * is the default.
5467 *
5468 * See [method@Gtk.Widget.set_receives_default].
5469 *
5470 * Returns: %TRUE if @widget acts as the default widget when focused,
5471 * %FALSE otherwise
5472 */
5473gboolean
5474gtk_widget_get_receives_default (GtkWidget *widget)
5475{
5476 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
5477
5478 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
5479
5480 return priv->receives_default;
5481}
5482
5483/*< private >
5484 * gtk_widget_has_grab:
5485 * @widget: a `GtkWidget`
5486 *
5487 * Determines whether the widget is currently grabbing events, so it
5488 * is the only widget receiving input events (keyboard and mouse).
5489 *
5490 * See also gtk_grab_add().
5491 *
5492 * Returns: %TRUE if the widget is in the grab_widgets stack
5493 */
5494gboolean
5495gtk_widget_has_grab (GtkWidget *widget)
5496{
5497 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
5498
5499 if (!GTK_IS_WIDGET (widget)) return FALSE;
5500
5501 return priv->has_grab;
5502}
5503
5504void
5505_gtk_widget_set_has_grab (GtkWidget *widget,
5506 gboolean has_grab)
5507{
5508 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
5509
5510 priv->has_grab = has_grab;
5511}
5512
5513/**
5514 * gtk_widget_set_name: (attributes org.gtk.Method.set_property=name)
5515 * @widget: a `GtkWidget`
5516 * @name: name for the widget
5517 *
5518 * Sets a widgets name.
5519 *
5520 * Setting a name allows you to refer to the widget from a
5521 * CSS file. You can apply a style to widgets with a particular name
5522 * in the CSS file. See the documentation for the CSS syntax (on the
5523 * same page as the docs for [class@Gtk.StyleContext].
5524 *
5525 * Note that the CSS syntax has certain special characters to delimit
5526 * and represent elements in a selector (period, #, >, *...), so using
5527 * these will make your widget impossible to match by name. Any combination
5528 * of alphanumeric symbols, dashes and underscores will suffice.
5529 */
5530void
5531gtk_widget_set_name (GtkWidget *widget,
5532 const char *name)
5533{
5534 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
5535
5536 g_return_if_fail (GTK_IS_WIDGET (widget));
5537
5538 g_free (mem: priv->name);
5539 priv->name = g_strdup (str: name);
5540
5541 gtk_css_node_set_id (cssnode: priv->cssnode, id: g_quark_from_string (string: priv->name));
5542
5543 g_object_notify_by_pspec (G_OBJECT (widget), pspec: widget_props[PROP_NAME]);
5544}
5545
5546/**
5547 * gtk_widget_get_name: (attributes org.gtk.Method.get_property=name)
5548 * @widget: a `GtkWidget`
5549 *
5550 * Retrieves the name of a widget.
5551 *
5552 * See [method@Gtk.Widget.set_name] for the significance of widget names.
5553 *
5554 * Returns: name of the widget. This string is owned by GTK and
5555 * should not be modified or freed
5556 */
5557const char *
5558gtk_widget_get_name (GtkWidget *widget)
5559{
5560 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
5561
5562 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
5563
5564 if (priv->name)
5565 return priv->name;
5566 return G_OBJECT_TYPE_NAME (widget);
5567}
5568
5569static void
5570gtk_widget_update_state_flags (GtkWidget *widget,
5571 GtkStateFlags flags_to_set,
5572 GtkStateFlags flags_to_unset)
5573{
5574 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
5575
5576 /* Handle insensitive first, since it is propagated
5577 * differently throughout the widget hierarchy.
5578 */
5579 if ((priv->state_flags & GTK_STATE_FLAG_INSENSITIVE) && (flags_to_unset & GTK_STATE_FLAG_INSENSITIVE))
5580 gtk_widget_set_sensitive (widget, TRUE);
5581 else if (!(priv->state_flags & GTK_STATE_FLAG_INSENSITIVE) && (flags_to_set & GTK_STATE_FLAG_INSENSITIVE))
5582 gtk_widget_set_sensitive (widget, FALSE);
5583
5584 flags_to_set &= ~(GTK_STATE_FLAG_INSENSITIVE);
5585 flags_to_unset &= ~(GTK_STATE_FLAG_INSENSITIVE);
5586
5587 if (flags_to_set != 0 || flags_to_unset != 0)
5588 {
5589 GtkStateData data;
5590
5591 data.old_scale_factor = gtk_widget_get_scale_factor (widget);
5592 data.flags_to_set = flags_to_set;
5593 data.flags_to_unset = flags_to_unset;
5594
5595 gtk_widget_propagate_state (widget, data: &data);
5596 }
5597}
5598
5599/**
5600 * gtk_widget_set_state_flags:
5601 * @widget: a `GtkWidget`
5602 * @flags: State flags to turn on
5603 * @clear: Whether to clear state before turning on @flags
5604 *
5605 * Turns on flag values in the current widget state.
5606 *
5607 * Typical widget states are insensitive, prelighted, etc.
5608 *
5609 * This function accepts the values %GTK_STATE_FLAG_DIR_LTR and
5610 * %GTK_STATE_FLAG_DIR_RTL but ignores them. If you want to set
5611 * the widget's direction, use [method@Gtk.Widget.set_direction].
5612 *
5613 * This function is for use in widget implementations.
5614 */
5615void
5616gtk_widget_set_state_flags (GtkWidget *widget,
5617 GtkStateFlags flags,
5618 gboolean clear)
5619{
5620 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
5621
5622#define ALLOWED_FLAGS (~(GTK_STATE_FLAG_DIR_LTR | GTK_STATE_FLAG_DIR_RTL))
5623
5624 g_return_if_fail (GTK_IS_WIDGET (widget));
5625
5626 if ((!clear && (priv->state_flags & flags) == flags) ||
5627 (clear && priv->state_flags == flags))
5628 return;
5629
5630 if (clear)
5631 gtk_widget_update_state_flags (widget, flags_to_set: flags & ALLOWED_FLAGS, flags_to_unset: ~flags & ALLOWED_FLAGS);
5632 else
5633 gtk_widget_update_state_flags (widget, flags_to_set: flags & ALLOWED_FLAGS, flags_to_unset: 0);
5634
5635#undef ALLOWED_FLAGS
5636}
5637
5638/**
5639 * gtk_widget_unset_state_flags:
5640 * @widget: a `GtkWidget`
5641 * @flags: State flags to turn off
5642 *
5643 * Turns off flag values for the current widget state.
5644 *
5645 * See [method@Gtk.Widget.set_state_flags].
5646 *
5647 * This function is for use in widget implementations.
5648 */
5649void
5650gtk_widget_unset_state_flags (GtkWidget *widget,
5651 GtkStateFlags flags)
5652{
5653 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
5654
5655 g_return_if_fail (GTK_IS_WIDGET (widget));
5656
5657 if ((priv->state_flags & flags) == 0)
5658 return;
5659
5660 gtk_widget_update_state_flags (widget, flags_to_set: 0, flags_to_unset: flags);
5661}
5662
5663/**
5664 * gtk_widget_get_state_flags:
5665 * @widget: a `GtkWidget`
5666 *
5667 * Returns the widget state as a flag set.
5668 *
5669 * It is worth mentioning that the effective %GTK_STATE_FLAG_INSENSITIVE
5670 * state will be returned, that is, also based on parent insensitivity,
5671 * even if @widget itself is sensitive.
5672 *
5673 * Also note that if you are looking for a way to obtain the
5674 * [flags@Gtk.StateFlags] to pass to a [class@Gtk.StyleContext]
5675 * method, you should look at [method@Gtk.StyleContext.get_state].
5676 *
5677 * Returns: The state flags for widget
5678 */
5679GtkStateFlags
5680gtk_widget_get_state_flags (GtkWidget *widget)
5681{
5682 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
5683
5684 g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
5685
5686 return priv->state_flags;
5687}
5688
5689/**
5690 * gtk_widget_set_visible: (attributes org.gtk.Method.set_property=visible)
5691 * @widget: a `GtkWidget`
5692 * @visible: whether the widget should be shown or not
5693 *
5694 * Sets the visibility state of @widget.
5695 *
5696 * Note that setting this to %TRUE doesn’t mean the widget is
5697 * actually viewable, see [method@Gtk.Widget.get_visible].
5698 *
5699 * This function simply calls [method@Gtk.Widget.show] or
5700 * [method@Gtk.Widget.hide] but is nicer to use when the
5701 * visibility of the widget depends on some condition.
5702 */
5703void
5704gtk_widget_set_visible (GtkWidget *widget,
5705 gboolean visible)
5706{
5707 g_return_if_fail (GTK_IS_WIDGET (widget));
5708
5709 if (visible)
5710 gtk_widget_show (widget);
5711 else
5712 gtk_widget_hide (widget);
5713}
5714
5715void
5716_gtk_widget_set_visible_flag (GtkWidget *widget,
5717 gboolean visible)
5718{
5719 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
5720
5721 priv->visible = visible;
5722
5723 if (!visible)
5724 {
5725 g_clear_pointer (&priv->allocated_transform, gsk_transform_unref);
5726 priv->allocated_width = 0;
5727 priv->allocated_height = 0;
5728 priv->allocated_size_baseline = 0;
5729 g_clear_pointer (&priv->transform, gsk_transform_unref);
5730 priv->width = 0;
5731 priv->height = 0;
5732 gtk_widget_update_paintables (widget);
5733 }
5734}
5735
5736/**
5737 * gtk_widget_get_visible: (attributes org.gtk.Method.get_property=visible)
5738 * @widget: a `GtkWidget`
5739 *
5740 * Determines whether the widget is visible.
5741 *
5742 * If you want to take into account whether the widget’s
5743 * parent is also marked as visible, use
5744 * [method@Gtk.Widget.is_visible] instead.
5745 *
5746 * This function does not check if the widget is
5747 * obscured in any way.
5748 *
5749 * See [method@Gtk.Widget.set_visible].
5750 *
5751 * Returns: %TRUE if the widget is visible
5752 */
5753gboolean
5754gtk_widget_get_visible (GtkWidget *widget)
5755{
5756 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
5757
5758 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
5759
5760 return priv->visible;
5761}
5762
5763/**
5764 * gtk_widget_is_visible:
5765 * @widget: a `GtkWidget`
5766 *
5767 * Determines whether the widget and all its parents are marked as
5768 * visible.
5769 *
5770 * This function does not check if the widget is obscured in any way.
5771 *
5772 * See also [method@Gtk.Widget.get_visible] and
5773 * [method@Gtk.Widget.set_visible].
5774 *
5775 * Returns: %TRUE if the widget and all its parents are visible
5776 */
5777gboolean
5778gtk_widget_is_visible (GtkWidget *widget)
5779{
5780 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
5781
5782 while (widget)
5783 {
5784 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
5785
5786 if (!priv->visible)
5787 return FALSE;
5788
5789 widget = priv->parent;
5790 }
5791
5792 return TRUE;
5793}
5794
5795/**
5796 * gtk_widget_is_drawable:
5797 * @widget: a `GtkWidget`
5798 *
5799 * Determines whether @widget can be drawn to.
5800 *
5801 * A widget can be drawn if it is mapped and visible.
5802 *
5803 * Returns: %TRUE if @widget is drawable, %FALSE otherwise
5804 */
5805gboolean
5806gtk_widget_is_drawable (GtkWidget *widget)
5807{
5808 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
5809
5810 return (_gtk_widget_get_visible (widget) &&
5811 _gtk_widget_get_mapped (widget));
5812}
5813
5814/**
5815 * gtk_widget_get_realized:
5816 * @widget: a `GtkWidget`
5817 *
5818 * Determines whether @widget is realized.
5819 *
5820 * Returns: %TRUE if @widget is realized, %FALSE otherwise
5821 */
5822gboolean
5823gtk_widget_get_realized (GtkWidget *widget)
5824{
5825 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
5826
5827 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
5828
5829 return priv->realized;
5830}
5831
5832/**
5833 * gtk_widget_get_mapped:
5834 * @widget: a `GtkWidget`
5835 *
5836 * Whether the widget is mapped.
5837 *
5838 * Returns: %TRUE if the widget is mapped, %FALSE otherwise.
5839 */
5840gboolean
5841gtk_widget_get_mapped (GtkWidget *widget)
5842{
5843 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
5844
5845 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
5846
5847 return priv->mapped;
5848}
5849
5850/**
5851 * gtk_widget_set_sensitive: (attributes org.gtk.Method.set_property=sensitive)
5852 * @widget: a `GtkWidget`
5853 * @sensitive: %TRUE to make the widget sensitive
5854 *
5855 * Sets the sensitivity of a widget.
5856 *
5857 * A widget is sensitive if the user can interact with it.
5858 * Insensitive widgets are “grayed out” and the user can’t
5859 * interact with them. Insensitive widgets are known as
5860 * “inactive”, “disabled”, or “ghosted” in some other toolkits.
5861 */
5862void
5863gtk_widget_set_sensitive (GtkWidget *widget,
5864 gboolean sensitive)
5865{
5866 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
5867 GList *l;
5868
5869 g_return_if_fail (GTK_IS_WIDGET (widget));
5870
5871 sensitive = (sensitive != FALSE);
5872
5873 if (priv->sensitive == sensitive)
5874 return;
5875
5876 priv->sensitive = sensitive;
5877
5878 for (l = priv->event_controllers; l; l = l->next)
5879 {
5880 GtkEventController *controller = l->data;
5881
5882 gtk_event_controller_reset (controller);
5883 }
5884
5885 gtk_accessible_update_state (self: GTK_ACCESSIBLE (ptr: widget),
5886 first_state: GTK_ACCESSIBLE_STATE_DISABLED, !sensitive,
5887 -1);
5888
5889 if (priv->parent == NULL
5890 || gtk_widget_is_sensitive (widget: priv->parent))
5891 {
5892 GtkStateData data;
5893
5894 data.old_scale_factor = gtk_widget_get_scale_factor (widget);
5895
5896 if (sensitive)
5897 {
5898 data.flags_to_set = 0;
5899 data.flags_to_unset = GTK_STATE_FLAG_INSENSITIVE;
5900 }
5901 else
5902 {
5903 data.flags_to_set = GTK_STATE_FLAG_INSENSITIVE;
5904 data.flags_to_unset = GTK_STATE_FLAG_PRELIGHT |
5905 GTK_STATE_FLAG_ACTIVE;
5906 }
5907
5908 gtk_widget_propagate_state (widget, data: &data);
5909 update_cursor_on_state_change (widget);
5910 }
5911
5912 g_object_notify_by_pspec (G_OBJECT (widget), pspec: widget_props[PROP_SENSITIVE]);
5913}
5914
5915/**
5916 * gtk_widget_get_sensitive: (attributes org.gtk.Method.get_property=sensitive)
5917 * @widget: a `GtkWidget`
5918 *
5919 * Returns the widget’s sensitivity.
5920 *
5921 * This function returns the value that has been set using
5922 * [method@Gtk.Widget.set_sensitive]).
5923 *
5924 * The effective sensitivity of a widget is however determined
5925 * by both its own and its parent widget’s sensitivity.
5926 * See [method@Gtk.Widget.is_sensitive].
5927 *
5928 * Returns: %TRUE if the widget is sensitive
5929 */
5930gboolean
5931gtk_widget_get_sensitive (GtkWidget *widget)
5932{
5933 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
5934
5935 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
5936
5937 return priv->sensitive;
5938}
5939
5940/**
5941 * gtk_widget_is_sensitive:
5942 * @widget: a `GtkWidget`
5943 *
5944 * Returns the widget’s effective sensitivity.
5945 *
5946 * This means it is sensitive itself and also its
5947 * parent widget is sensitive.
5948 *
5949 * Returns: %TRUE if the widget is effectively sensitive
5950 */
5951gboolean
5952gtk_widget_is_sensitive (GtkWidget *widget)
5953{
5954 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
5955
5956 return _gtk_widget_is_sensitive (widget);
5957}
5958
5959
5960/* Insert @widget into the children list of @parent,
5961 * after @previous_sibling */
5962static void
5963gtk_widget_reposition_after (GtkWidget *widget,
5964 GtkWidget *parent,
5965 GtkWidget *previous_sibling)
5966{
5967 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
5968 GtkStateFlags parent_flags;
5969 GtkWidget *prev_parent, *prev_previous;
5970 GtkStateData data;
5971
5972 prev_parent = priv->parent;
5973 prev_previous = priv->prev_sibling;
5974
5975 if (priv->parent != NULL && priv->parent != parent)
5976 {
5977 g_warning ("Can't set new parent %s %p on widget %s %p, "
5978 "which already has parent %s %p",
5979 gtk_widget_get_name (parent), (void *)parent,
5980 gtk_widget_get_name (widget), (void *)widget,
5981 gtk_widget_get_name (priv->parent), (void *)priv->parent);
5982 return;
5983 }
5984
5985 data.old_scale_factor = gtk_widget_get_scale_factor (widget);
5986
5987 if (priv->parent == NULL)
5988 g_object_ref_sink (widget);
5989
5990 gtk_widget_push_verify_invariants (widget);
5991
5992 priv->parent = parent;
5993
5994 if (previous_sibling)
5995 {
5996 if (previous_sibling->priv->next_sibling)
5997 previous_sibling->priv->next_sibling->priv->prev_sibling = widget;
5998
5999 if (priv->prev_sibling)
6000 priv->prev_sibling->priv->next_sibling = priv->next_sibling;
6001
6002 if (priv->next_sibling)
6003 priv->next_sibling->priv->prev_sibling = priv->prev_sibling;
6004
6005
6006 if (parent->priv->first_child == widget)
6007 parent->priv->first_child = priv->next_sibling;
6008
6009 if (parent->priv->last_child == widget)
6010 parent->priv->last_child = priv->prev_sibling;
6011
6012 priv->prev_sibling = previous_sibling;
6013 priv->next_sibling = previous_sibling->priv->next_sibling;
6014 previous_sibling->priv->next_sibling = widget;
6015
6016 if (parent->priv->last_child == previous_sibling)
6017 parent->priv->last_child = widget;
6018 else if (parent->priv->last_child == widget)
6019 parent->priv->last_child = priv->next_sibling;
6020 }
6021 else
6022 {
6023 /* Beginning */
6024 if (parent->priv->last_child == widget)
6025 {
6026 parent->priv->last_child = priv->prev_sibling;
6027 if (priv->prev_sibling)
6028 priv->prev_sibling->priv->next_sibling = NULL;
6029 }
6030 if (priv->prev_sibling)
6031 priv->prev_sibling->priv->next_sibling = priv->next_sibling;
6032
6033 if (priv->next_sibling)
6034 priv->next_sibling->priv->prev_sibling = priv->prev_sibling;
6035
6036 priv->prev_sibling = NULL;
6037 priv->next_sibling = parent->priv->first_child;
6038 if (parent->priv->first_child)
6039 parent->priv->first_child->priv->prev_sibling = widget;
6040
6041 parent->priv->first_child = widget;
6042
6043 if (parent->priv->last_child == NULL)
6044 parent->priv->last_child = widget;
6045 }
6046
6047 parent_flags = _gtk_widget_get_state_flags (widget: parent);
6048
6049 /* Merge both old state and current parent state,
6050 * making sure to only propagate the right states */
6051 data.flags_to_set = parent_flags & GTK_STATE_FLAGS_DO_SET_PROPAGATE;
6052 data.flags_to_unset = 0;
6053 gtk_widget_propagate_state (widget, data: &data);
6054
6055 gtk_css_node_insert_after (parent: parent->priv->cssnode,
6056 cssnode: priv->cssnode,
6057 previous_sibling: previous_sibling ? previous_sibling->priv->cssnode : NULL);
6058
6059 _gtk_widget_update_parent_muxer (widget);
6060
6061 if (parent->priv->root && priv->root == NULL)
6062 gtk_widget_root (widget);
6063
6064 if (parent->priv->children_observer)
6065 {
6066 if (prev_previous)
6067 gtk_list_list_model_item_moved (self: parent->priv->children_observer, item: widget, previous_previous: prev_previous);
6068 else
6069 gtk_list_list_model_item_added (self: parent->priv->children_observer, item: widget);
6070 }
6071
6072 if (prev_parent == NULL)
6073 g_object_notify_by_pspec (G_OBJECT (widget), pspec: widget_props[PROP_PARENT]);
6074
6075 /* Enforce mapped invariants */
6076 if (_gtk_widget_get_visible (widget: priv->parent) &&
6077 _gtk_widget_get_visible (widget))
6078 {
6079 if (_gtk_widget_get_child_visible (widget) &&
6080 _gtk_widget_get_mapped (widget: priv->parent))
6081 gtk_widget_map (widget);
6082
6083 gtk_widget_queue_resize (widget: priv->parent);
6084 }
6085
6086 /* child may cause parent's expand to change, if the child is
6087 * expanded. If child is not expanded, then it can't modify the
6088 * parent's expand. If the child becomes expanded later then it will
6089 * queue compute_expand then. This optimization plus defaulting
6090 * newly-constructed widgets to need_compute_expand=FALSE should
6091 * mean that initially building a widget tree doesn't have to keep
6092 * walking up setting need_compute_expand on parents over and over.
6093 *
6094 * We can't change a parent to need to expand unless we're visible.
6095 */
6096 if (_gtk_widget_get_visible (widget) &&
6097 (priv->need_compute_expand ||
6098 priv->computed_hexpand ||
6099 priv->computed_vexpand))
6100 {
6101 gtk_widget_queue_compute_expand (widget: parent);
6102 }
6103
6104 if (prev_parent == NULL)
6105 gtk_accessible_update_children (self: GTK_ACCESSIBLE (ptr: parent),
6106 child: GTK_ACCESSIBLE (ptr: widget),
6107 state: GTK_ACCESSIBLE_CHILD_STATE_ADDED);
6108
6109 gtk_widget_pop_verify_invariants (widget);
6110}
6111
6112/**
6113 * gtk_widget_set_parent: (attributes org.gtk.Method.set_property=parent)
6114 * @widget: a `GtkWidget`
6115 * @parent: parent widget
6116 *
6117 * Sets @parent as the parent widget of @widget.
6118 *
6119 * This takes care of details such as updating the state and style
6120 * of the child to reflect its new location and resizing the parent.
6121 * The opposite function is [method@Gtk.Widget.unparent].
6122 *
6123 * This function is useful only when implementing subclasses of
6124 * `GtkWidget`.
6125 */
6126void
6127gtk_widget_set_parent (GtkWidget *widget,
6128 GtkWidget *parent)
6129{
6130 g_return_if_fail (GTK_IS_WIDGET (widget));
6131 g_return_if_fail (GTK_IS_WIDGET (parent));
6132 g_return_if_fail (_gtk_widget_get_parent (widget) == NULL);
6133
6134 gtk_widget_reposition_after (widget,
6135 parent,
6136 previous_sibling: _gtk_widget_get_last_child (widget: parent));
6137}
6138
6139/**
6140 * gtk_widget_get_parent: (attributes org.gtk.Method.get_property=parent)
6141 * @widget: a `GtkWidget`
6142 *
6143 * Returns the parent widget of @widget.
6144 *
6145 * Returns: (transfer none) (nullable): the parent widget of @widget
6146 */
6147GtkWidget *
6148gtk_widget_get_parent (GtkWidget *widget)
6149{
6150 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
6151
6152 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
6153
6154 return priv->parent;
6155}
6156
6157/**
6158 * gtk_widget_get_root: (attributes org.gtk.Method.get_property=root)
6159 * @widget: a `GtkWidget`
6160 *
6161 * Returns the `GtkRoot` widget of @widget.
6162 *
6163 * This function will return %NULL if the widget is not contained
6164 * inside a widget tree with a root widget.
6165 *
6166 * `GtkRoot` widgets will return themselves here.
6167 *
6168 * Returns: (transfer none) (nullable): the root widget of @widget
6169 */
6170GtkRoot *
6171gtk_widget_get_root (GtkWidget *widget)
6172{
6173 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
6174
6175 return _gtk_widget_get_root (widget);
6176}
6177
6178/**
6179 * gtk_widget_get_native:
6180 * @widget: a `GtkWidget`
6181 *
6182 * Returns the nearest `GtkNative` ancestor of @widget.
6183 *
6184 * This function will return %NULL if the widget is not
6185 * contained inside a widget tree with a native ancestor.
6186 *
6187 * `GtkNative` widgets will return themselves here.
6188 *
6189 * Returns: (transfer none) (nullable): the `GtkNative` ancestor of @widget
6190 */
6191GtkNative *
6192gtk_widget_get_native (GtkWidget *widget)
6193{
6194 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
6195
6196 return (GtkNative *)gtk_widget_get_ancestor (widget, GTK_TYPE_NATIVE);
6197}
6198
6199static void
6200gtk_widget_real_direction_changed (GtkWidget *widget,
6201 GtkTextDirection previous_direction)
6202{
6203 gtk_widget_queue_resize (widget);
6204}
6205
6206#ifdef G_ENABLE_CONSISTENCY_CHECKS
6207
6208/* Verify invariants, see docs/widget_system.txt for notes on much of
6209 * this. Invariants may be temporarily broken while we’re in the
6210 * process of updating state, of course, so you can only
6211 * verify_invariants() after a given operation is complete.
6212 * Use push/pop_verify_invariants to help with that.
6213 */
6214static void
6215gtk_widget_verify_invariants (GtkWidget *widget)
6216{
6217 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
6218 GtkWidget *parent;
6219
6220 if (priv->verifying_invariants_count > 0)
6221 return;
6222
6223 parent = priv->parent;
6224
6225 if (priv->mapped)
6226 {
6227 /* Mapped implies ... */
6228
6229 if (!priv->realized)
6230 g_warning ("%s %p is mapped but not realized",
6231 gtk_widget_get_name (widget), widget);
6232
6233 if (!priv->visible)
6234 g_warning ("%s %p is mapped but not visible",
6235 gtk_widget_get_name (widget), widget);
6236
6237 if (!priv->child_visible && !GTK_IS_ROOT (widget))
6238 g_warning ("%s %p is mapped but not child_visible",
6239 gtk_widget_get_name (widget), widget);
6240 }
6241 else
6242 {
6243 /* Not mapped implies... */
6244
6245#if 0
6246 /* This check makes sense for normal toplevels, but for
6247 * something like a toplevel that is embedded within a clutter
6248 * state, mapping may depend on external factors.
6249 */
6250 if (widget->priv->toplevel)
6251 {
6252 if (widget->priv->visible)
6253 g_warning ("%s %p toplevel is visible but not mapped",
6254 G_OBJECT_TYPE_NAME (widget), widget);
6255 }
6256#endif
6257 }
6258
6259 /* Parent related checks aren't possible if parent has
6260 * verifying_invariants_count > 0 because parent needs to recurse
6261 * children first before the invariants will hold.
6262 */
6263 if (parent == NULL || parent->priv->verifying_invariants_count == 0)
6264 {
6265 if (parent &&
6266 parent->priv->realized)
6267 {
6268 /* Parent realized implies... */
6269
6270#if 0
6271 /* This is in widget_system.txt but appears to fail
6272 * because there's no gtk_container_realize() that
6273 * realizes all children... instead we just lazily
6274 * wait for map to fix things up.
6275 */
6276 if (!widget->priv->realized)
6277 g_warning ("%s %p is realized but child %s %p is not realized",
6278 G_OBJECT_TYPE_NAME (parent), parent,
6279 G_OBJECT_TYPE_NAME (widget), widget);
6280#endif
6281 }
6282 else if (priv->realized && !GTK_IS_ROOT (widget))
6283 {
6284 /* No parent or parent not realized on non-toplevel implies... */
6285 g_warning ("%s %p is not realized but child %s %p is realized",
6286 parent ? gtk_widget_get_name (parent) : "no parent", parent,
6287 gtk_widget_get_name (widget), widget);
6288 }
6289
6290 if (parent &&
6291 parent->priv->mapped &&
6292 priv->visible &&
6293 priv->child_visible)
6294 {
6295 /* Parent mapped and we are visible implies... */
6296
6297 if (!priv->mapped)
6298 g_warning ("%s %p is mapped but visible child %s %p is not mapped",
6299 gtk_widget_get_name (parent), parent,
6300 gtk_widget_get_name (widget), widget);
6301 }
6302 else if (priv->mapped && !GTK_IS_ROOT (widget))
6303 {
6304 /* No parent or parent not mapped on non-toplevel implies... */
6305 g_warning ("%s %p is mapped but visible=%d child_visible=%d parent %s %p mapped=%d",
6306 gtk_widget_get_name (widget), widget,
6307 priv->visible,
6308 priv->child_visible,
6309 parent ? gtk_widget_get_name (parent) : "no parent", parent,
6310 parent ? parent->priv->mapped : FALSE);
6311 }
6312 }
6313
6314 if (!priv->realized)
6315 {
6316 /* Not realized implies... */
6317
6318#if 0
6319 /* widget_system.txt says these hold, but they don't. */
6320 if (widget->priv->alloc_needed)
6321 g_warning ("%s %p alloc needed but not realized",
6322 G_OBJECT_TYPE_NAME (widget), widget);
6323
6324 if (widget->priv->width_request_needed)
6325 g_warning ("%s %p width request needed but not realized",
6326 G_OBJECT_TYPE_NAME (widget), widget);
6327
6328 if (widget->priv->height_request_needed)
6329 g_warning ("%s %p height request needed but not realized",
6330 G_OBJECT_TYPE_NAME (widget), widget);
6331#endif
6332 }
6333}
6334
6335/* The point of this push/pop is that invariants may not hold while
6336 * we’re busy making changes. So we only check at the outermost call
6337 * on the call stack, after we finish updating everything.
6338 */
6339static void
6340gtk_widget_push_verify_invariants (GtkWidget *widget)
6341{
6342 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
6343
6344 priv->verifying_invariants_count += 1;
6345}
6346
6347static void
6348gtk_widget_pop_verify_invariants (GtkWidget *widget)
6349{
6350 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
6351
6352 g_assert (priv->verifying_invariants_count > 0);
6353
6354 priv->verifying_invariants_count -= 1;
6355
6356 if (priv->verifying_invariants_count == 0)
6357 {
6358 GtkWidget *child;
6359 gtk_widget_verify_invariants (widget);
6360
6361 /* Check one level of children, because our
6362 * push_verify_invariants() will have prevented some of the
6363 * checks. This does not recurse because if recursion is
6364 * needed, it will happen naturally as each child has a
6365 * push/pop on that child. For example if we're recursively
6366 * mapping children, we'll push/pop on each child as we map
6367 * it.
6368 */
6369 for (child = _gtk_widget_get_first_child (widget);
6370 child != NULL;
6371 child = _gtk_widget_get_next_sibling (child))
6372 {
6373 gtk_widget_verify_invariants (child);
6374 }
6375 }
6376}
6377#endif /* G_ENABLE_CONSISTENCY_CHECKS */
6378
6379static PangoContext *
6380gtk_widget_peek_pango_context (GtkWidget *widget)
6381{
6382 return g_object_get_qdata (G_OBJECT (widget), quark: quark_pango_context);
6383}
6384
6385/**
6386 * gtk_widget_get_pango_context:
6387 * @widget: a `GtkWidget`
6388 *
6389 * Gets a `PangoContext` with the appropriate font map, font description,
6390 * and base direction for this widget.
6391 *
6392 * Unlike the context returned by [method@Gtk.Widget.create_pango_context],
6393 * this context is owned by the widget (it can be used until the screen
6394 * for the widget changes or the widget is removed from its toplevel),
6395 * and will be updated to match any changes to the widget’s attributes.
6396 * This can be tracked by listening to changes of the
6397 * [property@Gtk.Widget:root] property on the widget.
6398 *
6399 * Returns: (transfer none): the `PangoContext` for the widget.
6400 */
6401PangoContext *
6402gtk_widget_get_pango_context (GtkWidget *widget)
6403{
6404 PangoContext *context;
6405
6406 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
6407
6408 context = g_object_get_qdata (G_OBJECT (widget), quark: quark_pango_context);
6409 if (!context)
6410 {
6411 context = gtk_widget_create_pango_context (GTK_WIDGET (widget));
6412 g_object_set_qdata_full (G_OBJECT (widget),
6413 quark: quark_pango_context,
6414 data: context,
6415 destroy: g_object_unref);
6416 }
6417
6418 return context;
6419}
6420
6421static PangoFontMap *
6422gtk_widget_get_effective_font_map (GtkWidget *widget)
6423{
6424 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
6425 PangoFontMap *font_map;
6426
6427 font_map = PANGO_FONT_MAP (g_object_get_qdata (G_OBJECT (widget), quark_font_map));
6428 if (font_map)
6429 return font_map;
6430 else if (priv->parent)
6431 return gtk_widget_get_effective_font_map (widget: priv->parent);
6432 else
6433 return pango_cairo_font_map_get_default ();
6434}
6435
6436gboolean
6437gtk_widget_update_pango_context (GtkWidget *widget,
6438 PangoContext *context,
6439 GtkTextDirection direction)
6440{
6441 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
6442 GtkCssStyle *style = gtk_css_node_get_style (cssnode: priv->cssnode);
6443 PangoFontDescription *font_desc;
6444 GtkSettings *settings;
6445 cairo_font_options_t *font_options;
6446 guint old_serial;
6447
6448 old_serial = pango_context_get_serial (context);
6449
6450 font_desc = gtk_css_style_get_pango_font (style);
6451 pango_context_set_font_description (context, desc: font_desc);
6452 pango_font_description_free (desc: font_desc);
6453
6454 settings = gtk_widget_get_settings (widget);
6455
6456 if (settings &&
6457 cairo_version () >= CAIRO_VERSION_ENCODE (1, 17, 4))
6458 {
6459 gboolean hint_font_metrics;
6460
6461 g_object_get (object: settings, first_property_name: "gtk-hint-font-metrics", &hint_font_metrics, NULL);
6462 pango_context_set_round_glyph_positions (context, round_positions: hint_font_metrics);
6463 }
6464
6465 if (direction != GTK_TEXT_DIR_NONE)
6466 pango_context_set_base_dir (context, direction: direction == GTK_TEXT_DIR_LTR
6467 ? PANGO_DIRECTION_LTR
6468 : PANGO_DIRECTION_RTL);
6469
6470 pango_cairo_context_set_resolution (context, dpi: _gtk_css_number_value_get (number: style->core->dpi, one_hundred_percent: 100));
6471
6472 font_options = (cairo_font_options_t*)g_object_get_qdata (G_OBJECT (widget), quark: quark_font_options);
6473 if (settings && font_options)
6474 {
6475 cairo_font_options_t *options;
6476
6477 options = cairo_font_options_copy (original: gtk_settings_get_font_options (settings));
6478 cairo_font_options_merge (options, other: font_options);
6479 pango_cairo_context_set_font_options (context, options);
6480 cairo_font_options_destroy (options);
6481 }
6482 else if (settings)
6483 {
6484 pango_cairo_context_set_font_options (context,
6485 options: gtk_settings_get_font_options (settings));
6486 }
6487
6488 pango_context_set_font_map (context, font_map: gtk_widget_get_effective_font_map (widget));
6489
6490 return old_serial != pango_context_get_serial (context);
6491}
6492
6493static void
6494gtk_widget_update_default_pango_context (GtkWidget *widget)
6495{
6496 PangoContext *context = gtk_widget_peek_pango_context (widget);
6497
6498 if (!context)
6499 return;
6500
6501 if (gtk_widget_update_pango_context (widget, context, direction: _gtk_widget_get_direction (widget)))
6502 gtk_widget_queue_draw (widget);
6503}
6504
6505/**
6506 * gtk_widget_set_font_options:
6507 * @widget: a `GtkWidget`
6508 * @options: (nullable): a `cairo_font_options_t`
6509 * to unset any previously set default font options
6510 *
6511 * Sets the `cairo_font_options_t` used for Pango rendering
6512 * in this widget.
6513 *
6514 * When not set, the default font options for the `GdkDisplay`
6515 * will be used.
6516 */
6517void
6518gtk_widget_set_font_options (GtkWidget *widget,
6519 const cairo_font_options_t *options)
6520{
6521 cairo_font_options_t *font_options;
6522
6523 g_return_if_fail (GTK_IS_WIDGET (widget));
6524
6525 font_options = (cairo_font_options_t *)g_object_get_qdata (G_OBJECT (widget), quark: quark_font_options);
6526 if (font_options != options)
6527 {
6528 g_object_set_qdata_full (G_OBJECT (widget),
6529 quark: quark_font_options,
6530 data: options ? cairo_font_options_copy (original: options) : NULL,
6531 destroy: (GDestroyNotify)cairo_font_options_destroy);
6532
6533 gtk_widget_update_default_pango_context (widget);
6534 }
6535}
6536
6537/**
6538 * gtk_widget_get_font_options:
6539 * @widget: a `GtkWidget`
6540 *
6541 * Returns the `cairo_font_options_t` of widget.
6542 *
6543 * Seee [method@Gtk.Widget.set_font_options].
6544 *
6545 * Returns: (transfer none) (nullable): the `cairo_font_options_t`
6546 * of widget
6547 */
6548const cairo_font_options_t *
6549gtk_widget_get_font_options (GtkWidget *widget)
6550{
6551 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
6552
6553 return (cairo_font_options_t *)g_object_get_qdata (G_OBJECT (widget), quark: quark_font_options);
6554}
6555
6556static void
6557gtk_widget_set_font_map_recurse (GtkWidget *widget, gpointer user_data)
6558{
6559 if (g_object_get_qdata (G_OBJECT (widget), quark: quark_font_map))
6560 return;
6561
6562 gtk_widget_update_default_pango_context (widget);
6563
6564 gtk_widget_forall (widget, callback: gtk_widget_set_font_map_recurse, user_data);
6565}
6566
6567/**
6568 * gtk_widget_set_font_map:
6569 * @widget: a `GtkWidget`
6570 * @font_map: (nullable): a `PangoFontMap`, or %NULL to unset any
6571 * previously set font map
6572 *
6573 * Sets the font map to use for Pango rendering.
6574 *
6575 * The font map is the object that is used to look up fonts.
6576 * Setting a custom font map can be useful in special situations,
6577 * e.g. when you need to add application-specific fonts to the set
6578 * of available fonts.
6579 *
6580 * When not set, the widget will inherit the font map from its parent.
6581 */
6582void
6583gtk_widget_set_font_map (GtkWidget *widget,
6584 PangoFontMap *font_map)
6585{
6586 PangoFontMap *map;
6587
6588 g_return_if_fail (GTK_IS_WIDGET (widget));
6589
6590 map = PANGO_FONT_MAP (g_object_get_qdata (G_OBJECT (widget), quark_font_map));
6591 if (map == font_map)
6592 return;
6593
6594 g_object_set_qdata_full (G_OBJECT (widget),
6595 quark: quark_font_map,
6596 g_object_ref (font_map),
6597 destroy: g_object_unref);
6598
6599 gtk_widget_update_default_pango_context (widget);
6600
6601 gtk_widget_forall (widget, callback: gtk_widget_set_font_map_recurse, NULL);
6602}
6603
6604/**
6605 * gtk_widget_get_font_map:
6606 * @widget: a `GtkWidget`
6607 *
6608 * Gets the font map of @widget.
6609 *
6610 * See [method@Gtk.Widget.set_font_map].
6611 *
6612 * Returns: (transfer none) (nullable): A `PangoFontMap`
6613 */
6614PangoFontMap *
6615gtk_widget_get_font_map (GtkWidget *widget)
6616{
6617 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
6618
6619 return PANGO_FONT_MAP (g_object_get_qdata (G_OBJECT (widget), quark_font_map));
6620}
6621
6622/**
6623 * gtk_widget_create_pango_context:
6624 * @widget: a `GtkWidget`
6625 *
6626 * Creates a new `PangoContext` with the appropriate font map,
6627 * font options, font description, and base direction for drawing
6628 * text for this widget.
6629 *
6630 * See also [method@Gtk.Widget.get_pango_context].
6631 *
6632 * Returns: (transfer full): the new `PangoContext`
6633 */
6634PangoContext *
6635gtk_widget_create_pango_context (GtkWidget *widget)
6636{
6637 PangoContext *context;
6638
6639 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
6640
6641 context = pango_font_map_create_context (fontmap: pango_cairo_font_map_get_default ());
6642 gtk_widget_update_pango_context (widget, context, direction: _gtk_widget_get_direction (widget));
6643 pango_context_set_language (context, language: gtk_get_default_language ());
6644
6645 return context;
6646}
6647
6648/**
6649 * gtk_widget_create_pango_layout:
6650 * @widget: a `GtkWidget`
6651 * @text: (nullable): text to set on the layout
6652 *
6653 * Creates a new `PangoLayout` with the appropriate font map,
6654 * font description, and base direction for drawing text for
6655 * this widget.
6656 *
6657 * If you keep a `PangoLayout` created in this way around,
6658 * you need to re-create it when the widget `PangoContext`
6659 * is replaced. This can be tracked by listening to changes
6660 * of the [property@Gtk.Widget:root] property on the widget.
6661 *
6662 * Returns: (transfer full): the new `PangoLayout`
6663 **/
6664PangoLayout *
6665gtk_widget_create_pango_layout (GtkWidget *widget,
6666 const char *text)
6667{
6668 PangoLayout *layout;
6669 PangoContext *context;
6670
6671 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
6672
6673 context = gtk_widget_get_pango_context (widget);
6674 layout = pango_layout_new (context);
6675
6676 if (text)
6677 pango_layout_set_text (layout, text, length: -1);
6678
6679 return layout;
6680}
6681
6682/**
6683 * gtk_widget_set_child_visible:
6684 * @widget: a `GtkWidget`
6685 * @child_visible: if %TRUE, @widget should be mapped along
6686 * with its parent.
6687 *
6688 * Sets whether @widget should be mapped along with its parent.
6689 *
6690 * The child visibility can be set for widget before it is added
6691 * to a container with [method@Gtk.Widget.set_parent], to avoid
6692 * mapping children unnecessary before immediately unmapping them.
6693 * However it will be reset to its default state of %TRUE when the
6694 * widget is removed from a container.
6695 *
6696 * Note that changing the child visibility of a widget does not
6697 * queue a resize on the widget. Most of the time, the size of
6698 * a widget is computed from all visible children, whether or
6699 * not they are mapped. If this is not the case, the container
6700 * can queue a resize itself.
6701 *
6702 * This function is only useful for container implementations
6703 * and should never be called by an application.
6704 */
6705void
6706gtk_widget_set_child_visible (GtkWidget *widget,
6707 gboolean child_visible)
6708{
6709 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
6710
6711 g_return_if_fail (GTK_IS_WIDGET (widget));
6712 g_return_if_fail (!GTK_IS_ROOT (widget));
6713
6714 child_visible = !!child_visible;
6715
6716 if (priv->child_visible == child_visible)
6717 return;
6718
6719 g_object_ref (widget);
6720 gtk_widget_verify_invariants (widget);
6721
6722 if (child_visible)
6723 priv->child_visible = TRUE;
6724 else
6725 {
6726 GtkRoot *root;
6727
6728 priv->child_visible = FALSE;
6729
6730 root = _gtk_widget_get_root (widget);
6731 if (GTK_WIDGET (root) != widget && GTK_IS_WINDOW (root))
6732 _gtk_window_unset_focus_and_default (GTK_WINDOW (root), widget);
6733 }
6734
6735 if (priv->parent && _gtk_widget_get_realized (widget: priv->parent))
6736 {
6737 if (_gtk_widget_get_mapped (widget: priv->parent) &&
6738 priv->child_visible &&
6739 _gtk_widget_get_visible (widget))
6740 gtk_widget_map (widget);
6741 else
6742 gtk_widget_unmap (widget);
6743 }
6744
6745 gtk_widget_verify_invariants (widget);
6746 g_object_unref (object: widget);
6747}
6748
6749/**
6750 * gtk_widget_get_child_visible:
6751 * @widget: a `GtkWidget`
6752 *
6753 * Gets the value set with gtk_widget_set_child_visible().
6754 *
6755 * If you feel a need to use this function, your code probably
6756 * needs reorganization.
6757 *
6758 * This function is only useful for container implementations
6759 * and should never be called by an application.
6760 *
6761 * Returns: %TRUE if the widget is mapped with the parent.
6762 */
6763gboolean
6764gtk_widget_get_child_visible (GtkWidget *widget)
6765{
6766 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
6767
6768 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
6769
6770 return priv->child_visible;
6771}
6772
6773void
6774_gtk_widget_scale_changed (GtkWidget *widget)
6775{
6776 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
6777
6778 g_return_if_fail (GTK_IS_WIDGET (widget));
6779
6780 if (priv->context)
6781 gtk_style_context_set_scale (context: priv->context, scale: gtk_widget_get_scale_factor (widget));
6782
6783 g_object_notify_by_pspec (G_OBJECT (widget), pspec: widget_props[PROP_SCALE_FACTOR]);
6784
6785 gtk_widget_queue_draw (widget);
6786
6787 gtk_widget_forall (widget, callback: (GtkCallback)_gtk_widget_scale_changed, NULL);
6788}
6789
6790/**
6791 * gtk_widget_get_scale_factor: (attributes org.gtk.Method.get_property=scale-factor)
6792 * @widget: a `GtkWidget`
6793 *
6794 * Retrieves the internal scale factor that maps from window
6795 * coordinates to the actual device pixels.
6796 *
6797 * On traditional systems this is 1, on high density outputs,
6798 * it can be a higher value (typically 2).
6799 *
6800 * See [method@Gdk.Surface.get_scale_factor].
6801 *
6802 * Returns: the scale factor for @widget
6803 */
6804int
6805gtk_widget_get_scale_factor (GtkWidget *widget)
6806{
6807 GtkWidget *root;
6808 GdkDisplay *display;
6809 GdkMonitor *monitor;
6810
6811 g_return_val_if_fail (GTK_IS_WIDGET (widget), 1);
6812
6813 if (_gtk_widget_get_realized (widget))
6814 {
6815 GdkSurface *surface = gtk_widget_get_surface (widget);
6816
6817 if (surface)
6818 return gdk_surface_get_scale_factor (surface);
6819 }
6820
6821 root = (GtkWidget *)_gtk_widget_get_root (widget);
6822 if (root && root != widget)
6823 return gtk_widget_get_scale_factor (widget: root);
6824
6825 /* else fall back to something that is more likely to be right than
6826 * just returning 1:
6827 */
6828 display = _gtk_widget_get_display (widget);
6829 if (display)
6830 {
6831 monitor = g_list_model_get_item (list: gdk_display_get_monitors (self: display), position: 0);
6832 if (monitor)
6833 {
6834 int result = gdk_monitor_get_scale_factor (monitor);
6835 g_object_unref (object: monitor);
6836 return result;
6837 }
6838 }
6839
6840 return 1;
6841}
6842
6843/**
6844 * gtk_widget_get_display:
6845 * @widget: a `GtkWidget`
6846 *
6847 * Get the `GdkDisplay` for the toplevel window associated with
6848 * this widget.
6849 *
6850 * This function can only be called after the widget has been
6851 * added to a widget hierarchy with a `GtkWindow` at the top.
6852 *
6853 * In general, you should only create display specific
6854 * resources when a widget has been realized, and you should
6855 * free those resources when the widget is unrealized.
6856 *
6857 * Returns: (transfer none): the `GdkDisplay` for the toplevel
6858 * for this widget.
6859 */
6860GdkDisplay *
6861gtk_widget_get_display (GtkWidget *widget)
6862{
6863 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
6864
6865 return _gtk_widget_get_display (widget);
6866}
6867
6868/**
6869 * gtk_widget_child_focus:
6870 * @widget: a `GtkWidget`
6871 * @direction: direction of focus movement
6872 *
6873 * Called by widgets as the user moves around the window using
6874 * keyboard shortcuts.
6875 *
6876 * The @direction argument indicates what kind of motion is taking place (up,
6877 * down, left, right, tab forward, tab backward).
6878 *
6879 * This function calls the [vfunc@Gtk.Widget.focus] virtual function; widgets
6880 * can override the virtual function in order to implement appropriate focus
6881 * behavior.
6882 *
6883 * The default `focus()` virtual function for a widget should return `TRUE` if
6884 * moving in @direction left the focus on a focusable location inside that
6885 * widget, and `FALSE` if moving in @direction moved the focus outside the
6886 * widget. When returning `TRUE`, widgets normallycall [method@Gtk.Widget.grab_focus]
6887 * to place the focus accordingly; when returning `FALSE`, they don’t modify
6888 * the current focus location.
6889 *
6890 * This function is used by custom widget implementations; if you're
6891 * writing an app, you’d use [method@Gtk.Widget.grab_focus] to move
6892 * the focus to a particular widget.
6893 *
6894 * Returns: %TRUE if focus ended up inside @widget
6895 */
6896gboolean
6897gtk_widget_child_focus (GtkWidget *widget,
6898 GtkDirectionType direction)
6899{
6900 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
6901
6902 if (!_gtk_widget_get_visible (widget) ||
6903 !gtk_widget_is_sensitive (widget) ||
6904 !gtk_widget_get_can_focus (widget))
6905 return FALSE;
6906
6907 /* Emit ::focus in any case, even if focusable is FALSE,
6908 * since any widget might have child widgets that will take
6909 * focus
6910 */
6911
6912 return GTK_WIDGET_GET_CLASS (widget)->focus (widget, direction);
6913}
6914
6915/**
6916 * gtk_widget_keynav_failed:
6917 * @widget: a `GtkWidget`
6918 * @direction: direction of focus movement
6919 *
6920 * Emits the `::keynav-failed` signal on the widget.
6921 *
6922 * This function should be called whenever keyboard navigation
6923 * within a single widget hits a boundary.
6924 *
6925 * The return value of this function should be interpreted
6926 * in a way similar to the return value of
6927 * [method@Gtk.Widget.child_focus]. When %TRUE is returned,
6928 * stay in the widget, the failed keyboard navigation is OK
6929 * and/or there is nowhere we can/should move the focus to.
6930 * When %FALSE is returned, the caller should continue with
6931 * keyboard navigation outside the widget, e.g. by calling
6932 * [method@Gtk.Widget.child_focus] on the widget’s toplevel.
6933 *
6934 * The default [signal@Gtk.Widget::keynav-failed] handler returns
6935 * %FALSE for %GTK_DIR_TAB_FORWARD and %GTK_DIR_TAB_BACKWARD.
6936 * For the other values of `GtkDirectionType` it returns %TRUE.
6937 *
6938 * Whenever the default handler returns %TRUE, it also calls
6939 * [method@Gtk.Widget.error_bell] to notify the user of the
6940 * failed keyboard navigation.
6941 *
6942 * A use case for providing an own implementation of ::keynav-failed
6943 * (either by connecting to it or by overriding it) would be a row of
6944 * [class@Gtk.Entry] widgets where the user should be able to navigate
6945 * the entire row with the cursor keys, as e.g. known from user
6946 * interfaces that require entering license keys.
6947 *
6948 * Returns: %TRUE if stopping keyboard navigation is fine, %FALSE
6949 * if the emitting widget should try to handle the keyboard
6950 * navigation attempt in its parent container(s).
6951 */
6952gboolean
6953gtk_widget_keynav_failed (GtkWidget *widget,
6954 GtkDirectionType direction)
6955{
6956 gboolean return_val;
6957
6958 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
6959
6960 g_signal_emit (instance: widget, signal_id: widget_signals[KEYNAV_FAILED], detail: 0,
6961 direction, &return_val);
6962
6963 return return_val;
6964}
6965
6966/**
6967 * gtk_widget_error_bell:
6968 * @widget: a `GtkWidget`
6969 *
6970 * Notifies the user about an input-related error on this widget.
6971 *
6972 * If the [property@Gtk.Settings:gtk-error-bell] setting is %TRUE,
6973 * it calls [method@Gdk.Surface.beep], otherwise it does nothing.
6974 *
6975 * Note that the effect of [method@Gdk.Surface.beep] can be configured
6976 * in many ways, depending on the windowing backend and the desktop
6977 * environment or window manager that is used.
6978 */
6979void
6980gtk_widget_error_bell (GtkWidget *widget)
6981{
6982 GtkSettings* settings;
6983 gboolean beep;
6984 GdkSurface *surface;
6985
6986 g_return_if_fail (GTK_IS_WIDGET (widget));
6987
6988 settings = gtk_widget_get_settings (widget);
6989 if (!settings)
6990 return;
6991
6992 surface = gtk_widget_get_surface (widget);
6993
6994 g_object_get (object: settings,
6995 first_property_name: "gtk-error-bell", &beep,
6996 NULL);
6997
6998 if (beep && surface)
6999 gdk_surface_beep (surface);
7000}
7001
7002static void
7003gtk_widget_set_usize_internal (GtkWidget *widget,
7004 int width,
7005 int height)
7006{
7007 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
7008 gboolean changed = FALSE;
7009
7010 g_object_freeze_notify (G_OBJECT (widget));
7011
7012 if (width > -2 && priv->width_request != width)
7013 {
7014 g_object_notify_by_pspec (G_OBJECT (widget), pspec: widget_props[PROP_WIDTH_REQUEST]);
7015 priv->width_request = width;
7016 changed = TRUE;
7017 }
7018 if (height > -2 && priv->height_request != height)
7019 {
7020 g_object_notify_by_pspec (G_OBJECT (widget), pspec: widget_props[PROP_HEIGHT_REQUEST]);
7021 priv->height_request = height;
7022 changed = TRUE;
7023 }
7024
7025 if (_gtk_widget_get_visible (widget) && changed)
7026 {
7027 gtk_widget_queue_resize (widget);
7028 }
7029
7030 g_object_thaw_notify (G_OBJECT (widget));
7031}
7032
7033/**
7034 * gtk_widget_set_size_request:
7035 * @widget: a `GtkWidget`
7036 * @width: width @widget should request, or -1 to unset
7037 * @height: height @widget should request, or -1 to unset
7038 *
7039 * Sets the minimum size of a widget.
7040 *
7041 * That is, the widget’s size request will be at least @width
7042 * by @height. You can use this function to force a widget to
7043 * be larger than it normally would be.
7044 *
7045 * In most cases, [method@Gtk.Window.set_default_size] is a better
7046 * choice for toplevel windows than this function; setting the default
7047 * size will still allow users to shrink the window. Setting the size
7048 * request will force them to leave the window at least as large as
7049 * the size request.
7050 *
7051 * Note the inherent danger of setting any fixed size - themes,
7052 * translations into other languages, different fonts, and user action
7053 * can all change the appropriate size for a given widget. So, it's
7054 * basically impossible to hardcode a size that will always be
7055 * correct.
7056 *
7057 * The size request of a widget is the smallest size a widget can
7058 * accept while still functioning well and drawing itself correctly.
7059 * However in some strange cases a widget may be allocated less than
7060 * its requested size, and in many cases a widget may be allocated more
7061 * space than it requested.
7062 *
7063 * If the size request in a given direction is -1 (unset), then
7064 * the “natural” size request of the widget will be used instead.
7065 *
7066 * The size request set here does not include any margin from the
7067 * properties
7068 * [property@Gtk.Widget:margin-start],
7069 * [property@Gtk.Widget:margin-end],
7070 * [property@Gtk.Widget:margin-top], and
7071 * [property@Gtk.Widget:margin-bottom], but it does include pretty
7072 * much all other padding or border properties set by any subclass
7073 * of `GtkWidget`.
7074 */
7075void
7076gtk_widget_set_size_request (GtkWidget *widget,
7077 int width,
7078 int height)
7079{
7080 g_return_if_fail (GTK_IS_WIDGET (widget));
7081 g_return_if_fail (width >= -1);
7082 g_return_if_fail (height >= -1);
7083
7084 gtk_widget_set_usize_internal (widget, width, height);
7085}
7086
7087
7088/**
7089 * gtk_widget_get_size_request:
7090 * @widget: a `GtkWidget`
7091 * @width: (out) (optional): return location for width
7092 * @height: (out) (optional): return location for height
7093 *
7094 * Gets the size request that was explicitly set for the widget using
7095 * gtk_widget_set_size_request().
7096 *
7097 * A value of -1 stored in @width or @height indicates that that
7098 * dimension has not been set explicitly and the natural requisition
7099 * of the widget will be used instead. See
7100 * [method@Gtk.Widget.set_size_request]. To get the size a widget will
7101 * actually request, call [method@Gtk.Widget.measure] instead of
7102 * this function.
7103 */
7104void
7105gtk_widget_get_size_request (GtkWidget *widget,
7106 int *width,
7107 int *height)
7108{
7109 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
7110
7111 g_return_if_fail (GTK_IS_WIDGET (widget));
7112
7113 if (width)
7114 *width = priv->width_request;
7115
7116 if (height)
7117 *height = priv->height_request;
7118}
7119
7120/*< private >
7121 * gtk_widget_has_size_request:
7122 * @widget: a `GtkWidget`
7123 *
7124 * Returns if the widget has a size request set (anything besides -1 for height
7125 * or width)
7126 */
7127gboolean
7128gtk_widget_has_size_request (GtkWidget *widget)
7129{
7130 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
7131
7132 return !(priv->width_request == -1 && priv->height_request == -1);
7133}
7134
7135/**
7136 * gtk_widget_get_ancestor:
7137 * @widget: a `GtkWidget`
7138 * @widget_type: ancestor type
7139 *
7140 * Gets the first ancestor of @widget with type @widget_type.
7141 *
7142 * For example, `gtk_widget_get_ancestor (widget, GTK_TYPE_BOX)`
7143 * gets the first `GtkBox` that’s an ancestor of @widget. No
7144 * reference will be added to the returned widget; it should
7145 * not be unreferenced.
7146 *
7147 * Note that unlike [method@Gtk.Widget.is_ancestor], this function
7148 * considers @widget to be an ancestor of itself.
7149 *
7150 * Returns: (transfer none) (nullable): the ancestor widget
7151 */
7152GtkWidget*
7153gtk_widget_get_ancestor (GtkWidget *widget,
7154 GType widget_type)
7155{
7156 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
7157
7158 while (widget && !g_type_is_a (G_OBJECT_TYPE (widget), is_a_type: widget_type))
7159 {
7160 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
7161
7162 widget = priv->parent;
7163 }
7164
7165 return widget;
7166}
7167
7168/**
7169 * gtk_widget_get_settings:
7170 * @widget: a `GtkWidget`
7171 *
7172 * Gets the settings object holding the settings used for this widget.
7173 *
7174 * Note that this function can only be called when the `GtkWidget`
7175 * is attached to a toplevel, since the settings object is specific
7176 * to a particular `GdkDisplay`. If you want to monitor the widget for
7177 * changes in its settings, connect to the `notify::display` signal.
7178 *
7179 * Returns: (transfer none): the relevant `GtkSettings` object
7180 */
7181GtkSettings*
7182gtk_widget_get_settings (GtkWidget *widget)
7183{
7184 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
7185
7186 return gtk_settings_get_for_display (display: _gtk_widget_get_display (widget));
7187}
7188
7189/**
7190 * gtk_widget_is_ancestor:
7191 * @widget: a `GtkWidget`
7192 * @ancestor: another `GtkWidget`
7193 *
7194 * Determines whether @widget is somewhere inside @ancestor,
7195 * possibly with intermediate containers.
7196 *
7197 * Returns: %TRUE if @ancestor contains @widget as a child,
7198 * grandchild, great grandchild, etc.
7199 */
7200gboolean
7201gtk_widget_is_ancestor (GtkWidget *widget,
7202 GtkWidget *ancestor)
7203{
7204 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
7205 g_return_val_if_fail (ancestor != NULL, FALSE);
7206
7207 while (widget)
7208 {
7209 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
7210
7211 if (priv->parent == ancestor)
7212 return TRUE;
7213
7214 widget = priv->parent;
7215 }
7216
7217 return FALSE;
7218}
7219
7220static void
7221gtk_widget_emit_direction_changed (GtkWidget *widget,
7222 GtkTextDirection old_dir)
7223{
7224 GtkTextDirection direction;
7225 GtkStateFlags state;
7226
7227 gtk_widget_update_default_pango_context (widget);
7228
7229 direction = _gtk_widget_get_direction (widget);
7230
7231 switch (direction)
7232 {
7233 case GTK_TEXT_DIR_LTR:
7234 state = GTK_STATE_FLAG_DIR_LTR;
7235 break;
7236
7237 case GTK_TEXT_DIR_RTL:
7238 state = GTK_STATE_FLAG_DIR_RTL;
7239 break;
7240
7241 case GTK_TEXT_DIR_NONE:
7242 default:
7243 g_assert_not_reached ();
7244 break;
7245 }
7246
7247 gtk_widget_update_state_flags (widget,
7248 flags_to_set: state,
7249 flags_to_unset: state ^ (GTK_STATE_FLAG_DIR_LTR | GTK_STATE_FLAG_DIR_RTL));
7250
7251 g_signal_emit (instance: widget, signal_id: widget_signals[DIRECTION_CHANGED], detail: 0, old_dir);
7252}
7253
7254/**
7255 * gtk_widget_set_direction:
7256 * @widget: a `GtkWidget`
7257 * @dir: the new direction
7258 *
7259 * Sets the reading direction on a particular widget.
7260 *
7261 * This direction controls the primary direction for widgets
7262 * containing text, and also the direction in which the children
7263 * of a container are packed. The ability to set the direction is
7264 * present in order so that correct localization into languages with
7265 * right-to-left reading directions can be done. Generally, applications
7266 * will let the default reading direction present, except for containers
7267 * where the containers are arranged in an order that is explicitly
7268 * visual rather than logical (such as buttons for text justification).
7269 *
7270 * If the direction is set to %GTK_TEXT_DIR_NONE, then the value
7271 * set by [func@Gtk.Widget.set_default_direction] will be used.
7272 */
7273void
7274gtk_widget_set_direction (GtkWidget *widget,
7275 GtkTextDirection dir)
7276{
7277 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
7278 GtkTextDirection old_dir;
7279
7280 g_return_if_fail (GTK_IS_WIDGET (widget));
7281 g_return_if_fail (dir >= GTK_TEXT_DIR_NONE && dir <= GTK_TEXT_DIR_RTL);
7282
7283 old_dir = _gtk_widget_get_direction (widget);
7284
7285 priv->direction = dir;
7286
7287 if (old_dir != _gtk_widget_get_direction (widget))
7288 gtk_widget_emit_direction_changed (widget, old_dir);
7289}
7290
7291/**
7292 * gtk_widget_get_direction:
7293 * @widget: a `GtkWidget`
7294 *
7295 * Gets the reading direction for a particular widget.
7296 *
7297 * See [method@Gtk.Widget.set_direction].
7298 *
7299 * Returns: the reading direction for the widget.
7300 */
7301GtkTextDirection
7302gtk_widget_get_direction (GtkWidget *widget)
7303{
7304 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
7305
7306 g_return_val_if_fail (GTK_IS_WIDGET (widget), GTK_TEXT_DIR_LTR);
7307
7308 if (priv->direction == GTK_TEXT_DIR_NONE)
7309 return gtk_default_direction;
7310 else
7311 return priv->direction;
7312}
7313
7314static void
7315gtk_widget_set_default_direction_recurse (GtkWidget *widget,
7316 GtkTextDirection old_dir)
7317{
7318 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
7319 GtkWidget *child;
7320
7321 g_object_ref (widget);
7322
7323 if (priv->direction == GTK_TEXT_DIR_NONE)
7324 gtk_widget_emit_direction_changed (widget, old_dir);
7325
7326 for (child = _gtk_widget_get_first_child (widget);
7327 child != NULL;
7328 child = _gtk_widget_get_next_sibling (widget: child))
7329 {
7330 gtk_widget_set_default_direction_recurse (widget: child, old_dir);
7331 }
7332
7333 g_object_unref (object: widget);
7334}
7335
7336/**
7337 * gtk_widget_set_default_direction:
7338 * @dir: the new default direction. This cannot be %GTK_TEXT_DIR_NONE.
7339 *
7340 * Sets the default reading direction for widgets.
7341 *
7342 * See [method@Gtk.Widget.set_direction].
7343 */
7344void
7345gtk_widget_set_default_direction (GtkTextDirection dir)
7346{
7347 g_return_if_fail (dir == GTK_TEXT_DIR_RTL || dir == GTK_TEXT_DIR_LTR);
7348
7349 if (dir != gtk_default_direction)
7350 {
7351 GList *toplevels, *tmp_list;
7352 GtkTextDirection old_dir = gtk_default_direction;
7353
7354 gtk_default_direction = dir;
7355
7356 tmp_list = toplevels = gtk_window_list_toplevels ();
7357 g_list_foreach (list: toplevels, func: (GFunc)g_object_ref, NULL);
7358
7359 while (tmp_list)
7360 {
7361 gtk_widget_set_default_direction_recurse (widget: tmp_list->data, old_dir);
7362 g_object_unref (object: tmp_list->data);
7363 tmp_list = tmp_list->next;
7364 }
7365
7366 g_list_free (list: toplevels);
7367 }
7368}
7369
7370/**
7371 * gtk_widget_get_default_direction:
7372 *
7373 * Obtains the current default reading direction.
7374 *
7375 * See [func@Gtk.Widget.set_default_direction].
7376 *
7377 * Returns: the current default direction.
7378 */
7379GtkTextDirection
7380gtk_widget_get_default_direction (void)
7381{
7382 return gtk_default_direction;
7383}
7384
7385static void
7386gtk_widget_dispose (GObject *object)
7387{
7388 GtkWidget *widget = GTK_WIDGET (object);
7389 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
7390 GSList *sizegroups;
7391 GtkATContext *at_context;
7392
7393 if (priv->muxer != NULL)
7394 g_object_run_dispose (G_OBJECT (priv->muxer));
7395
7396 if (priv->children_observer)
7397 gtk_list_list_model_clear (self: priv->children_observer);
7398 if (priv->controller_observer)
7399 gtk_list_list_model_clear (self: priv->controller_observer);
7400
7401 if (priv->parent)
7402 {
7403 g_critical ("%s %p has a parent %s %p during dispose. Parents hold a reference, so this should not happen.\n"
7404 "Did you call g_object_unref() instead of gtk_widget_unparent()?",
7405 G_OBJECT_TYPE_NAME (widget), widget,
7406 G_OBJECT_TYPE_NAME (priv->parent), priv->parent);
7407 priv->parent = NULL;
7408 }
7409
7410 while (priv->paintables)
7411 gtk_widget_paintable_set_widget (self: priv->paintables->data, NULL);
7412
7413 if (priv->layout_manager != NULL)
7414 gtk_layout_manager_set_widget (manager: priv->layout_manager, NULL);
7415 g_clear_object (&priv->layout_manager);
7416
7417 priv->visible = FALSE;
7418 if (_gtk_widget_get_realized (widget))
7419 gtk_widget_unrealize (widget);
7420
7421 g_clear_object (&priv->cursor);
7422
7423 if (!priv->in_destruction)
7424 {
7425 priv->in_destruction = TRUE;
7426 g_signal_emit (instance: object, signal_id: widget_signals[DESTROY], detail: 0);
7427 priv->in_destruction = FALSE;
7428 gtk_widget_real_destroy (object: widget);
7429 }
7430
7431 sizegroups = _gtk_widget_get_sizegroups (widget);
7432 while (sizegroups)
7433 {
7434 GtkSizeGroup *size_group;
7435
7436 size_group = sizegroups->data;
7437 sizegroups = sizegroups->next;
7438 gtk_size_group_remove_widget (size_group, widget);
7439 }
7440
7441 at_context = gtk_accessible_get_at_context (self: GTK_ACCESSIBLE (ptr: widget));
7442 if (at_context != NULL)
7443 gtk_at_context_unrealize (self: at_context);
7444
7445 g_clear_object (&priv->muxer);
7446
7447 G_OBJECT_CLASS (gtk_widget_parent_class)->dispose (object);
7448}
7449
7450#ifdef G_ENABLE_CONSISTENCY_CHECKS
7451typedef struct {
7452 AutomaticChildClass *child_class;
7453 GType widget_type;
7454 GObject *object;
7455 gboolean did_finalize;
7456} FinalizeAssertion;
7457
7458static void
7459finalize_assertion_weak_ref (gpointer data,
7460 GObject *where_the_object_was)
7461{
7462 FinalizeAssertion *assertion = (FinalizeAssertion *)data;
7463 assertion->did_finalize = TRUE;
7464}
7465#endif /* G_ENABLE_CONSISTENCY_CHECKS */
7466
7467static void
7468gtk_widget_real_destroy (GtkWidget *object)
7469{
7470 GtkWidget *widget = GTK_WIDGET (object);
7471
7472 if (g_object_get_qdata (G_OBJECT (widget), quark: quark_auto_children))
7473 {
7474 GtkWidgetClass *class;
7475 GSList *l;
7476
7477#ifdef G_ENABLE_CONSISTENCY_CHECKS
7478 GSList *assertions = NULL;
7479
7480 /* Note, GTK_WIDGET_ASSERT_COMPONENTS is very useful
7481 * to catch ref counting bugs, but can only be used in
7482 * test cases which simply create and destroy a composite
7483 * widget.
7484 *
7485 * This is because some API can expose components explicitly,
7486 * and so we cannot assert that a component is expected to finalize
7487 * in a full application ecosystem.
7488 */
7489 if (g_getenv ("GTK_WIDGET_ASSERT_COMPONENTS") != NULL)
7490 {
7491 GType class_type;
7492
7493 for (class = GTK_WIDGET_GET_CLASS (widget);
7494 GTK_IS_WIDGET_CLASS (class);
7495 class = g_type_class_peek_parent (class))
7496 {
7497 if (!class->priv->template)
7498 continue;
7499
7500 class_type = G_OBJECT_CLASS_TYPE (class);
7501
7502 for (l = class->priv->template->children; l; l = l->next)
7503 {
7504 AutomaticChildClass *child_class = l->data;
7505 GObject *child_object = gtk_widget_get_template_child (widget,
7506 class_type,
7507 child_class->name);
7508
7509 g_assert (child_object);
7510
7511 if (!G_IS_OBJECT (child_object))
7512 {
7513 g_critical ("Automated component '%s' of class '%s' seems to"
7514 " have been prematurely finalized",
7515 child_class->name, g_type_name (class_type));
7516 }
7517 else
7518 {
7519 FinalizeAssertion *assertion = g_slice_new0 (FinalizeAssertion);
7520 assertion->child_class = child_class;
7521 assertion->widget_type = class_type;
7522 assertion->object = child_object;
7523
7524 g_object_weak_ref (child_object, finalize_assertion_weak_ref, assertion);
7525
7526 assertions = g_slist_prepend (assertions, assertion);
7527 }
7528 }
7529 }
7530 }
7531#endif /* G_ENABLE_CONSISTENCY_CHECKS */
7532
7533 /* Release references to all automated children */
7534 g_object_set_qdata (G_OBJECT (widget), quark: quark_auto_children, NULL);
7535
7536#ifdef G_ENABLE_CONSISTENCY_CHECKS
7537 for (l = assertions; l; l = l->next)
7538 {
7539 FinalizeAssertion *assertion = l->data;
7540
7541 if (!assertion->did_finalize)
7542 g_critical ("Automated component '%s' of class '%s' did not finalize in dispose()"
7543 "Current reference count is %d",
7544 assertion->child_class->name,
7545 g_type_name (assertion->widget_type),
7546 assertion->object->ref_count);
7547
7548 g_slice_free (FinalizeAssertion, assertion);
7549 }
7550 g_slist_free (assertions);
7551#endif /* G_ENABLE_CONSISTENCY_CHECKS */
7552
7553 /* Set any automatic private data pointers to NULL */
7554 for (class = GTK_WIDGET_GET_CLASS (widget);
7555 GTK_IS_WIDGET_CLASS (class);
7556 class = g_type_class_peek_parent (g_class: class))
7557 {
7558 if (!class->priv->template)
7559 continue;
7560
7561 for (l = class->priv->template->children; l; l = l->next)
7562 {
7563 AutomaticChildClass *child_class = l->data;
7564
7565 if (child_class->offset != 0)
7566 {
7567 gpointer field_p;
7568
7569 /* Nullify instance private data for internal children */
7570 field_p = G_STRUCT_MEMBER_P (widget, child_class->offset);
7571 (* (gpointer *) field_p) = NULL;
7572 }
7573 }
7574 }
7575 }
7576
7577 /* Callers of add_mnemonic_label() should disconnect on ::destroy */
7578 g_object_set_qdata (G_OBJECT (widget), quark: quark_mnemonic_labels, NULL);
7579
7580 gtk_grab_remove (widget);
7581
7582 destroy_tick_callbacks (widget);
7583 destroy_surface_transform_data (widget);
7584}
7585
7586static void
7587gtk_widget_finalize (GObject *object)
7588{
7589 GtkWidget *widget = GTK_WIDGET (object);
7590 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
7591 GList *l;
7592
7593 gtk_grab_remove (widget);
7594
7595 g_free (mem: priv->name);
7596 g_free (mem: priv->tooltip_markup);
7597 g_free (mem: priv->tooltip_text);
7598
7599 g_clear_pointer (&priv->transform, gsk_transform_unref);
7600 g_clear_pointer (&priv->allocated_transform, gsk_transform_unref);
7601
7602 gtk_css_widget_node_widget_destroyed (GTK_CSS_WIDGET_NODE (priv->cssnode));
7603 g_object_unref (object: priv->cssnode);
7604
7605 g_clear_object (&priv->context);
7606 g_clear_object (&priv->at_context);
7607
7608 _gtk_size_request_cache_free (cache: &priv->requests);
7609
7610 l = priv->event_controllers;
7611 while (l)
7612 {
7613 GList *next = l->next;
7614 GtkEventController *controller = l->data;
7615
7616 if (controller)
7617 gtk_widget_remove_controller (widget, controller);
7618
7619 l = next;
7620 }
7621 g_assert (priv->event_controllers == NULL);
7622
7623 if (_gtk_widget_get_first_child (widget) != NULL)
7624 {
7625 GtkWidget *child;
7626 g_warning ("Finalizing %s %p, but it still has children left:",
7627 gtk_widget_get_name (widget), widget);
7628 for (child = _gtk_widget_get_first_child (widget);
7629 child != NULL;
7630 child = _gtk_widget_get_next_sibling (widget: child))
7631 {
7632 g_warning (" - %s %p", gtk_widget_get_name (child), child);
7633 }
7634 }
7635
7636 if (g_object_is_floating (object))
7637 g_warning ("A floating object was finalized. This means that someone\n"
7638 "called g_object_unref() on an object that had only a floating\n"
7639 "reference; the initial floating reference is not owned by anyone\n"
7640 "and must be removed with g_object_ref_sink().");
7641
7642 G_OBJECT_CLASS (gtk_widget_parent_class)->finalize (object);
7643}
7644
7645static void
7646gtk_widget_real_map (GtkWidget *widget)
7647{
7648 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
7649
7650 g_assert (_gtk_widget_get_realized (widget));
7651
7652 if (!_gtk_widget_get_mapped (widget))
7653 {
7654 GtkWidget *p;
7655 priv->mapped = TRUE;
7656
7657 for (p = gtk_widget_get_first_child (widget);
7658 p != NULL;
7659 p = gtk_widget_get_next_sibling (widget: p))
7660 {
7661 if (_gtk_widget_get_visible (widget: p) &&
7662 _gtk_widget_get_child_visible (widget: p) &&
7663 !_gtk_widget_get_mapped (widget: p))
7664 gtk_widget_map (widget: p);
7665 }
7666 }
7667}
7668
7669static void
7670gtk_widget_real_unmap (GtkWidget *widget)
7671{
7672 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
7673
7674 if (_gtk_widget_get_mapped (widget))
7675 {
7676 GtkWidget *child;
7677 priv->mapped = FALSE;
7678
7679 for (child = _gtk_widget_get_first_child (widget);
7680 child != NULL;
7681 child = _gtk_widget_get_next_sibling (widget: child))
7682 {
7683 gtk_widget_unmap (widget: child);
7684 }
7685
7686 gtk_widget_update_paintables (widget);
7687
7688 gtk_widget_unset_state_flags (widget,
7689 flags: GTK_STATE_FLAG_PRELIGHT |
7690 GTK_STATE_FLAG_ACTIVE);
7691 }
7692}
7693
7694static void
7695gtk_widget_real_realize (GtkWidget *widget)
7696{
7697 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
7698
7699 priv->realized = TRUE;
7700
7701 /* Connect frame clock */
7702 if (priv->tick_callbacks != NULL && !priv->clock_tick_id)
7703 {
7704 GdkFrameClock *frame_clock = gtk_widget_get_frame_clock (widget);
7705
7706 priv->clock_tick_id = g_signal_connect (frame_clock, "update",
7707 G_CALLBACK (gtk_widget_on_frame_clock_update),
7708 widget);
7709 gdk_frame_clock_begin_updating (frame_clock);
7710 }
7711
7712 gtk_css_node_invalidate_frame_clock (cssnode: priv->cssnode, FALSE);
7713}
7714
7715static void
7716gtk_widget_real_unrealize (GtkWidget *widget)
7717{
7718 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
7719
7720 g_assert (!priv->mapped);
7721
7722 /* We must do unrealize child widget BEFORE container widget.
7723 * gdk_surface_destroy() destroys specified xwindow and its sub-xwindows.
7724 * So, unrealizing container widget before its children causes the problem
7725 * (for example, gdk_ic_destroy () with destroyed window causes crash.)
7726 */
7727
7728 gtk_widget_forall (widget, callback: (GtkCallback)gtk_widget_unrealize, NULL);
7729
7730 /* Disconnect frame clock */
7731 gtk_css_node_invalidate_frame_clock (cssnode: priv->cssnode, FALSE);
7732
7733 if (priv->clock_tick_id)
7734 {
7735 GdkFrameClock *frame_clock = gtk_widget_get_frame_clock (widget);
7736
7737 g_signal_handler_disconnect (instance: frame_clock, handler_id: priv->clock_tick_id);
7738 priv->clock_tick_id = 0;
7739 gdk_frame_clock_end_updating (frame_clock);
7740 }
7741
7742 priv->realized = FALSE;
7743}
7744
7745void
7746gtk_widget_adjust_size_request (GtkWidget *widget,
7747 GtkOrientation orientation,
7748 int *minimum_size,
7749 int *natural_size)
7750{
7751 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
7752
7753 if (orientation == GTK_ORIENTATION_HORIZONTAL && priv->width_request > 0)
7754 *minimum_size = MAX (*minimum_size, priv->width_request);
7755 else if (orientation == GTK_ORIENTATION_VERTICAL && priv->height_request > 0)
7756 *minimum_size = MAX (*minimum_size, priv->height_request);
7757
7758 /* Fix it if set_size_request made natural size smaller than min size.
7759 * This would also silently fix broken widgets, but we warn about them
7760 * in gtksizerequest.c when calling their size request vfuncs.
7761 */
7762 *natural_size = MAX (*natural_size, *minimum_size);
7763
7764 if (orientation == GTK_ORIENTATION_HORIZONTAL)
7765 {
7766 *minimum_size += priv->margin.left + priv->margin.right;
7767 *natural_size += priv->margin.left + priv->margin.right;
7768 }
7769 else
7770 {
7771 *minimum_size += priv->margin.top + priv->margin.bottom;
7772 *natural_size += priv->margin.top + priv->margin.bottom;
7773 }
7774}
7775
7776void
7777gtk_widget_adjust_baseline_request (GtkWidget *widget,
7778 int *minimum_baseline,
7779 int *natural_baseline)
7780{
7781 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
7782
7783 if (priv->height_request >= 0)
7784 {
7785 /* No baseline support for explicitly set height */
7786 *minimum_baseline = -1;
7787 *natural_baseline = -1;
7788 }
7789 else
7790 {
7791 *minimum_baseline += priv->margin.top;
7792 *natural_baseline += priv->margin.top;
7793 }
7794}
7795
7796/*
7797 * _gtk_widget_list_devices:
7798 * @widget: a `GtkWidget`
7799 *
7800 * Returns the list of pointer `GdkDevice`s that are currently
7801 * on top of @widget. Free the list
7802 * with g_free(), the elements are owned by GTK and must
7803 * not be freed.
7804 */
7805static GdkDevice **
7806_gtk_widget_list_devices (GtkWidget *widget,
7807 guint *out_n_devices)
7808{
7809 GtkRoot *root;
7810
7811 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
7812 g_assert (out_n_devices);
7813
7814 if (!_gtk_widget_get_mapped (widget))
7815 {
7816 *out_n_devices = 0;
7817 return NULL;
7818 }
7819
7820 root = gtk_widget_get_root (widget);
7821 if (!GTK_IS_WINDOW (root))
7822 {
7823 *out_n_devices = 0;
7824 return NULL;
7825 }
7826
7827 return gtk_window_get_foci_on_widget (GTK_WINDOW (root),
7828 widget, n_devices: out_n_devices);
7829}
7830
7831/*
7832 * _gtk_widget_synthesize_crossing:
7833 * @from: the `GtkWidget` the virtual pointer is leaving.
7834 * @to: the `GtkWidget` the virtual pointer is moving to.
7835 * @mode: the `GdkCrossingMode` to place on the synthesized events.
7836 *
7837 * Generate crossing event(s) on widget state (sensitivity) or GTK grab change.
7838 */
7839void
7840_gtk_widget_synthesize_crossing (GtkWidget *from,
7841 GtkWidget *to,
7842 GdkDevice *device,
7843 GdkCrossingMode mode)
7844{
7845 GdkSurface *from_surface = NULL, *to_surface = NULL;
7846 GtkCrossingData crossing;
7847 double x, y;
7848
7849 g_return_if_fail (from != NULL || to != NULL);
7850
7851 crossing.type = GTK_CROSSING_POINTER;
7852 crossing.mode = mode;
7853 crossing.old_target = from;
7854 crossing.old_descendent = NULL;
7855 crossing.new_target = to;
7856 crossing.new_descendent = NULL;
7857
7858 if (from)
7859 {
7860 crossing.direction = GTK_CROSSING_OUT;
7861
7862 from_surface = gtk_widget_get_surface (widget: from);
7863 gdk_surface_get_device_position (surface: from_surface, device, x: &x, y: &y, NULL);
7864 gtk_widget_handle_crossing (widget: from, crossing: &crossing, x, y);
7865 }
7866
7867 if (to)
7868 {
7869 to_surface = gtk_widget_get_surface (widget: to);
7870
7871 crossing.direction = GTK_CROSSING_IN;
7872 gdk_surface_get_device_position (surface: to_surface, device, x: &x, y: &y, NULL);
7873 gtk_widget_handle_crossing (widget: to, crossing: &crossing, x, y);
7874 }
7875}
7876
7877static void
7878gtk_widget_propagate_state (GtkWidget *widget,
7879 const GtkStateData *data)
7880{
7881 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
7882 GtkStateFlags new_flags, old_flags = priv->state_flags;
7883 GtkStateData child_data;
7884 GtkWidget *child;
7885 int new_scale_factor = gtk_widget_get_scale_factor (widget);
7886
7887 priv->state_flags |= data->flags_to_set;
7888 priv->state_flags &= ~(data->flags_to_unset);
7889
7890 /* make insensitivity unoverridable */
7891 if (!priv->sensitive)
7892 priv->state_flags |= GTK_STATE_FLAG_INSENSITIVE;
7893
7894 if (gtk_widget_is_focus (widget) && !gtk_widget_is_sensitive (widget))
7895 gtk_root_set_focus (self: priv->root, NULL);
7896
7897 new_flags = priv->state_flags;
7898
7899 if (data->old_scale_factor != new_scale_factor)
7900 _gtk_widget_scale_changed (widget);
7901
7902 if (old_flags != new_flags)
7903 {
7904 GtkRoot *root;
7905 GtkWidget *grab = NULL;
7906 gboolean shadowed;
7907
7908 g_object_ref (widget);
7909
7910 root = gtk_widget_get_root (widget);
7911
7912 if (GTK_IS_WINDOW (root))
7913 {
7914 GtkWindowGroup *window_group;
7915
7916 window_group = gtk_window_get_group (GTK_WINDOW (root));
7917 grab = gtk_window_group_get_current_grab (window_group);
7918 }
7919
7920 shadowed = grab && grab != widget && !gtk_widget_is_ancestor (widget, ancestor: grab);
7921
7922 if (!gtk_widget_is_sensitive (widget) && gtk_widget_has_grab (widget))
7923 gtk_grab_remove (widget);
7924
7925 gtk_css_node_set_state (cssnode: priv->cssnode, state_flags: new_flags);
7926
7927 g_signal_emit (instance: widget, signal_id: widget_signals[STATE_FLAGS_CHANGED], detail: 0, old_flags);
7928
7929 if (!shadowed &&
7930 (new_flags & GTK_STATE_FLAG_INSENSITIVE) != (old_flags & GTK_STATE_FLAG_INSENSITIVE))
7931 {
7932 guint i, n_devices;
7933 GdkDevice **devices;
7934
7935 devices = _gtk_widget_list_devices (widget, out_n_devices: &n_devices);
7936
7937 for (i = 0; i < n_devices; i++)
7938 {
7939 GdkDevice *device;
7940
7941 device = devices[i];
7942
7943 if (!gtk_widget_is_sensitive (widget))
7944 _gtk_widget_synthesize_crossing (from: widget, NULL, device,
7945 mode: GDK_CROSSING_STATE_CHANGED);
7946 else
7947 _gtk_widget_synthesize_crossing (NULL, to: widget, device,
7948 mode: GDK_CROSSING_STATE_CHANGED);
7949 }
7950
7951 g_free (mem: devices);
7952 }
7953
7954 if (!gtk_widget_is_sensitive (widget))
7955 gtk_widget_reset_controllers (widget);
7956
7957 /* Make sure to only propagate the right states further */
7958 child_data.old_scale_factor = new_scale_factor;
7959 child_data.flags_to_set = data->flags_to_set & GTK_STATE_FLAGS_DO_SET_PROPAGATE;
7960 child_data.flags_to_unset = data->flags_to_unset & GTK_STATE_FLAGS_DO_UNSET_PROPAGATE;
7961
7962 if (child_data.flags_to_set != 0 ||
7963 child_data.flags_to_unset != 0)
7964 {
7965 for (child = _gtk_widget_get_first_child (widget);
7966 child != NULL;
7967 child = _gtk_widget_get_next_sibling (widget: child))
7968 {
7969 gtk_widget_propagate_state (widget: child, data: &child_data);
7970 }
7971 }
7972
7973 g_object_unref (object: widget);
7974 }
7975}
7976
7977/**
7978 * gtk_requisition_new:
7979 *
7980 * Allocates a new `GtkRequisition`.
7981 *
7982 * The struct is initialized to zero.
7983 *
7984 * Returns: a new empty `GtkRequisition`. The newly
7985 * allocated `GtkRequisition` should be freed with
7986 * [method@Gtk.Requisition.free]
7987 */
7988GtkRequisition *
7989gtk_requisition_new (void)
7990{
7991 return g_slice_new0 (GtkRequisition);
7992}
7993
7994/**
7995 * gtk_requisition_copy:
7996 * @requisition: a `GtkRequisition`
7997 *
7998 * Copies a `GtkRequisition`.
7999 *
8000 * Returns: a copy of @requisition
8001 */
8002GtkRequisition *
8003gtk_requisition_copy (const GtkRequisition *requisition)
8004{
8005 return g_slice_dup (GtkRequisition, requisition);
8006}
8007
8008/**
8009 * gtk_requisition_free:
8010 * @requisition: a `GtkRequisition`
8011 *
8012 * Frees a `GtkRequisition`.
8013 */
8014void
8015gtk_requisition_free (GtkRequisition *requisition)
8016{
8017 g_slice_free (GtkRequisition, requisition);
8018}
8019
8020G_DEFINE_BOXED_TYPE (GtkRequisition, gtk_requisition,
8021 gtk_requisition_copy,
8022 gtk_requisition_free)
8023
8024/*
8025 * Expand flag management
8026 */
8027
8028static void
8029gtk_widget_update_computed_expand (GtkWidget *widget)
8030{
8031 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
8032
8033 if (priv->need_compute_expand)
8034 {
8035 gboolean h, v;
8036
8037 if (priv->hexpand_set)
8038 h = priv->hexpand;
8039 else
8040 h = FALSE;
8041
8042 if (priv->vexpand_set)
8043 v = priv->vexpand;
8044 else
8045 v = FALSE;
8046
8047 /* we don't need to use compute_expand if both expands are
8048 * forced by the app
8049 */
8050 if (!(priv->hexpand_set && priv->vexpand_set))
8051 {
8052 if (GTK_WIDGET_GET_CLASS (widget)->compute_expand != NULL)
8053 {
8054 gboolean ignored;
8055
8056 GTK_WIDGET_GET_CLASS (widget)->compute_expand (widget,
8057 priv->hexpand_set ? &ignored : &h,
8058 priv->vexpand_set ? &ignored : &v);
8059 }
8060 }
8061
8062 priv->need_compute_expand = FALSE;
8063 priv->computed_hexpand = h != FALSE;
8064 priv->computed_vexpand = v != FALSE;
8065 }
8066}
8067
8068/**
8069 * gtk_widget_queue_compute_expand:
8070 * @widget: a `GtkWidget`
8071 *
8072 * Mark @widget as needing to recompute its expand flags.
8073 *
8074 * Call this function when setting legacy expand child
8075 * properties on the child of a container.
8076 *
8077 * See [method@Gtk.Widget.compute_expand].
8078 */
8079static void
8080gtk_widget_queue_compute_expand (GtkWidget *widget)
8081{
8082 GtkWidget *parent;
8083 gboolean changed_anything;
8084
8085 if (widget->priv->need_compute_expand)
8086 return;
8087
8088 changed_anything = FALSE;
8089 parent = widget;
8090 while (parent != NULL)
8091 {
8092 if (!parent->priv->need_compute_expand)
8093 {
8094 parent->priv->need_compute_expand = TRUE;
8095 changed_anything = TRUE;
8096 }
8097
8098 /* Note: if we had an invariant that "if a child needs to
8099 * compute expand, its parents also do" then we could stop going
8100 * up when we got to a parent that already needed to
8101 * compute. However, in general we compute expand lazily (as
8102 * soon as we see something in a subtree that is expand, we know
8103 * we're expanding) and so this invariant does not hold and we
8104 * have to always walk all the way up in case some ancestor
8105 * is not currently need_compute_expand.
8106 */
8107
8108 parent = parent->priv->parent;
8109 }
8110
8111 /* recomputing expand always requires
8112 * a relayout as well
8113 */
8114 if (changed_anything)
8115 gtk_widget_queue_resize (widget);
8116}
8117
8118/**
8119 * gtk_widget_compute_expand:
8120 * @widget: the widget
8121 * @orientation: expand direction
8122 *
8123 * Computes whether a container should give this widget
8124 * extra space when possible.
8125 *
8126 * Containers should check this, rather than looking at
8127 * [method@Gtk.Widget.get_hexpand] or [method@Gtk.Widget.get_vexpand].
8128 *
8129 * This function already checks whether the widget is visible, so
8130 * visibility does not need to be checked separately. Non-visible
8131 * widgets are not expanded.
8132 *
8133 * The computed expand value uses either the expand setting explicitly
8134 * set on the widget itself, or, if none has been explicitly set,
8135 * the widget may expand if some of its children do.
8136 *
8137 * Returns: whether widget tree rooted here should be expanded
8138 */
8139gboolean
8140gtk_widget_compute_expand (GtkWidget *widget,
8141 GtkOrientation orientation)
8142{
8143 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
8144
8145 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
8146
8147 /* We never make a widget expand if not even showing. */
8148 if (!_gtk_widget_get_visible (widget))
8149 return FALSE;
8150
8151 gtk_widget_update_computed_expand (widget);
8152
8153 if (orientation == GTK_ORIENTATION_HORIZONTAL)
8154 return priv->computed_hexpand;
8155 else
8156 return priv->computed_vexpand;
8157}
8158
8159static void
8160gtk_widget_set_expand (GtkWidget *widget,
8161 GtkOrientation orientation,
8162 gboolean expand)
8163{
8164 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
8165 int expand_prop;
8166 int expand_set_prop;
8167
8168 g_return_if_fail (GTK_IS_WIDGET (widget));
8169
8170 expand = expand != FALSE;
8171
8172 if (orientation == GTK_ORIENTATION_HORIZONTAL)
8173 {
8174 if (priv->hexpand_set &&
8175 priv->hexpand == expand)
8176 return;
8177
8178 priv->hexpand_set = TRUE;
8179 priv->hexpand = expand;
8180
8181 expand_prop = PROP_HEXPAND;
8182 expand_set_prop = PROP_HEXPAND_SET;
8183 }
8184 else
8185 {
8186 if (priv->vexpand_set &&
8187 priv->vexpand == expand)
8188 return;
8189
8190 priv->vexpand_set = TRUE;
8191 priv->vexpand = expand;
8192
8193 expand_prop = PROP_VEXPAND;
8194 expand_set_prop = PROP_VEXPAND_SET;
8195 }
8196
8197 gtk_widget_queue_compute_expand (widget);
8198
8199 g_object_freeze_notify (G_OBJECT (widget));
8200 g_object_notify_by_pspec (G_OBJECT (widget), pspec: widget_props[expand_prop]);
8201 g_object_notify_by_pspec (G_OBJECT (widget), pspec: widget_props[expand_set_prop]);
8202 g_object_thaw_notify (G_OBJECT (widget));
8203}
8204
8205static void
8206gtk_widget_set_expand_set (GtkWidget *widget,
8207 GtkOrientation orientation,
8208 gboolean set)
8209{
8210 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
8211 int prop;
8212
8213 set = set != FALSE;
8214
8215 if (orientation == GTK_ORIENTATION_HORIZONTAL)
8216 {
8217 if (set == priv->hexpand_set)
8218 return;
8219
8220 priv->hexpand_set = set;
8221 prop = PROP_HEXPAND_SET;
8222 }
8223 else
8224 {
8225 if (set == priv->vexpand_set)
8226 return;
8227
8228 priv->vexpand_set = set;
8229 prop = PROP_VEXPAND_SET;
8230 }
8231
8232 gtk_widget_queue_compute_expand (widget);
8233
8234 g_object_notify_by_pspec (G_OBJECT (widget), pspec: widget_props[prop]);
8235}
8236
8237/**
8238 * gtk_widget_get_hexpand: (attributes org.gtk.Method.get_property=hexpand)
8239 * @widget: the widget
8240 *
8241 * Gets whether the widget would like any available extra horizontal
8242 * space.
8243 *
8244 * When a user resizes a `GtkWindow`, widgets with expand=TRUE
8245 * generally receive the extra space. For example, a list or
8246 * scrollable area or document in your window would often be set to
8247 * expand.
8248 *
8249 * Containers should use [method@Gtk.Widget.compute_expand] rather
8250 * than this function, to see whether a widget, or any of its children,
8251 * has the expand flag set. If any child of a widget wants to
8252 * expand, the parent may ask to expand also.
8253 *
8254 * This function only looks at the widget’s own hexpand flag, rather
8255 * than computing whether the entire widget tree rooted at this widget
8256 * wants to expand.
8257 *
8258 * Returns: whether hexpand flag is set
8259 */
8260gboolean
8261gtk_widget_get_hexpand (GtkWidget *widget)
8262{
8263 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
8264
8265 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
8266
8267 return priv->hexpand;
8268}
8269
8270/**
8271 * gtk_widget_set_hexpand: (attributes org.gtk.Method.set_property=hexpand)
8272 * @widget: the widget
8273 * @expand: whether to expand
8274 *
8275 * Sets whether the widget would like any available extra horizontal
8276 * space.
8277 *
8278 * When a user resizes a `GtkWindow`, widgets with expand=TRUE
8279 * generally receive the extra space. For example, a list or
8280 * scrollable area or document in your window would often be set to
8281 * expand.
8282 *
8283 * Call this function to set the expand flag if you would like your
8284 * widget to become larger horizontally when the window has extra
8285 * room.
8286 *
8287 * By default, widgets automatically expand if any of their children
8288 * want to expand. (To see if a widget will automatically expand given
8289 * its current children and state, call [method@Gtk.Widget.compute_expand].
8290 * A container can decide how the expandability of children affects the
8291 * expansion of the container by overriding the compute_expand virtual
8292 * method on `GtkWidget`.).
8293 *
8294 * Setting hexpand explicitly with this function will override the
8295 * automatic expand behavior.
8296 *
8297 * This function forces the widget to expand or not to expand,
8298 * regardless of children. The override occurs because
8299 * [method@Gtk.Widget.set_hexpand] sets the hexpand-set property (see
8300 * [method@Gtk.Widget.set_hexpand_set]) which causes the widget’s hexpand
8301 * value to be used, rather than looking at children and widget state.
8302 */
8303void
8304gtk_widget_set_hexpand (GtkWidget *widget,
8305 gboolean expand)
8306{
8307 g_return_if_fail (GTK_IS_WIDGET (widget));
8308
8309 gtk_widget_set_expand (widget, orientation: GTK_ORIENTATION_HORIZONTAL, expand);
8310}
8311
8312/**
8313 * gtk_widget_get_hexpand_set: (attributes org.gtk.Method.get_property=hexpand-set)
8314 * @widget: the widget
8315 *
8316 * Gets whether gtk_widget_set_hexpand() has been used
8317 * to explicitly set the expand flag on this widget.
8318 *
8319 * If [property@Gtk.Widget:hexpand] property is set, then it
8320 * overrides any computed expand value based on child widgets.
8321 * If `hexpand` is not set, then the expand value depends on
8322 * whether any children of the widget would like to expand.
8323 *
8324 * There are few reasons to use this function, but it’s here
8325 * for completeness and consistency.
8326 *
8327 * Returns: whether hexpand has been explicitly set
8328 */
8329gboolean
8330gtk_widget_get_hexpand_set (GtkWidget *widget)
8331{
8332 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
8333
8334 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
8335
8336 return priv->hexpand_set;
8337}
8338
8339/**
8340 * gtk_widget_set_hexpand_set: (attributes org.gtk.Method.set_property=hexpand-set)
8341 * @widget: the widget
8342 * @set: value for hexpand-set property
8343 *
8344 * Sets whether the hexpand flag will be used.
8345 *
8346 * The [property@Gtk.Widget:hexpand-set] property will be set
8347 * automatically when you call [method@Gtk.Widget.set_hexpand]
8348 * to set hexpand, so the most likely reason to use this function
8349 * would be to unset an explicit expand flag.
8350 *
8351 * If hexpand is set, then it overrides any computed
8352 * expand value based on child widgets. If hexpand is not
8353 * set, then the expand value depends on whether any
8354 * children of the widget would like to expand.
8355 *
8356 * There are few reasons to use this function, but it’s here
8357 * for completeness and consistency.
8358 */
8359void
8360gtk_widget_set_hexpand_set (GtkWidget *widget,
8361 gboolean set)
8362{
8363 g_return_if_fail (GTK_IS_WIDGET (widget));
8364
8365 gtk_widget_set_expand_set (widget, orientation: GTK_ORIENTATION_HORIZONTAL, set);
8366}
8367
8368
8369/**
8370 * gtk_widget_get_vexpand: (attributes org.gtk.Method.get_property=vexpand)
8371 * @widget: the widget
8372 *
8373 * Gets whether the widget would like any available extra vertical
8374 * space.
8375 *
8376 * See [method@Gtk.Widget.get_hexpand] for more detail.
8377 *
8378 * Returns: whether vexpand flag is set
8379 */
8380gboolean
8381gtk_widget_get_vexpand (GtkWidget *widget)
8382{
8383 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
8384
8385 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
8386
8387 return priv->vexpand;
8388}
8389
8390/**
8391 * gtk_widget_set_vexpand: (attributes org.gtk.Method.set_property=vexpand)
8392 * @widget: the widget
8393 * @expand: whether to expand
8394 *
8395 * Sets whether the widget would like any available extra vertical
8396 * space.
8397 *
8398 * See [method@Gtk.Widget.set_hexpand] for more detail.
8399 */
8400void
8401gtk_widget_set_vexpand (GtkWidget *widget,
8402 gboolean expand)
8403{
8404 g_return_if_fail (GTK_IS_WIDGET (widget));
8405
8406 gtk_widget_set_expand (widget, orientation: GTK_ORIENTATION_VERTICAL, expand);
8407}
8408
8409/**
8410 * gtk_widget_get_vexpand_set: (attributes org.gtk.Method.get_property=vexpand-set)
8411 * @widget: the widget
8412 *
8413 * Gets whether gtk_widget_set_vexpand() has been used to
8414 * explicitly set the expand flag on this widget.
8415 *
8416 * See [method@Gtk.Widget.get_hexpand_set] for more detail.
8417 *
8418 * Returns: whether vexpand has been explicitly set
8419 */
8420gboolean
8421gtk_widget_get_vexpand_set (GtkWidget *widget)
8422{
8423 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
8424
8425 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
8426
8427 return priv->vexpand_set;
8428}
8429
8430/**
8431 * gtk_widget_set_vexpand_set: (attributes org.gtk.Method.set_property=vexpand-set)
8432 * @widget: the widget
8433 * @set: value for vexpand-set property
8434 *
8435 * Sets whether the vexpand flag will be used.
8436 *
8437 * See [method@Gtk.Widget.set_hexpand_set] for more detail.
8438 */
8439void
8440gtk_widget_set_vexpand_set (GtkWidget *widget,
8441 gboolean set)
8442{
8443 g_return_if_fail (GTK_IS_WIDGET (widget));
8444
8445 gtk_widget_set_expand_set (widget, orientation: GTK_ORIENTATION_VERTICAL, set);
8446}
8447
8448/*
8449 * GtkAccessible implementation
8450 */
8451
8452static GtkATContext *
8453gtk_widget_accessible_get_at_context (GtkAccessible *accessible)
8454{
8455 GtkWidget *self = GTK_WIDGET (accessible);
8456 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self);
8457 GtkWidgetClass *widget_class = GTK_WIDGET_GET_CLASS (self);
8458 GtkWidgetClassPrivate *class_priv = widget_class->priv;
8459 GtkAccessibleRole role;
8460
8461 if (priv->in_destruction)
8462 {
8463 GTK_NOTE (A11Y, g_message ("ATContext for widget “%s” [%p] accessed during destruction",
8464 G_OBJECT_TYPE_NAME (self),
8465 self));
8466 return NULL;
8467 }
8468
8469 if (priv->at_context != NULL)
8470 return priv->at_context;
8471
8472 /* Widgets have two options to set the accessible role: either they
8473 * define it in their class_init() function, and the role applies to
8474 * all instances; or an instance is created with the :accessible-role
8475 * property (from GtkAccessible) set to anything other than the default
8476 * GTK_ACCESSIBLE_ROLE_WIDGET value.
8477 *
8478 * In either case, the accessible role cannot be set post-construction.
8479 */
8480 if (priv->accessible_role != GTK_ACCESSIBLE_ROLE_WIDGET)
8481 role = priv->accessible_role;
8482 else
8483 role = class_priv->accessible_role;
8484
8485 priv->accessible_role = role;
8486 priv->at_context = gtk_at_context_create (accessible_role: role, accessible, display: gdk_display_get_default ());
8487
8488 return priv->at_context;
8489}
8490
8491static gboolean
8492gtk_widget_accessible_get_platform_state (GtkAccessible *self,
8493 GtkAccessiblePlatformState state)
8494{
8495 switch (state)
8496 {
8497 case GTK_ACCESSIBLE_PLATFORM_STATE_FOCUSABLE:
8498 return gtk_widget_get_focusable (GTK_WIDGET (self));
8499 case GTK_ACCESSIBLE_PLATFORM_STATE_FOCUSED:
8500 return gtk_widget_has_focus (GTK_WIDGET (self));
8501 case GTK_ACCESSIBLE_PLATFORM_STATE_ACTIVE:
8502 return FALSE;
8503 default:
8504 g_assert_not_reached ();
8505 }
8506}
8507
8508static void
8509gtk_widget_accessible_interface_init (GtkAccessibleInterface *iface)
8510{
8511 iface->get_at_context = gtk_widget_accessible_get_at_context;
8512 iface->get_platform_state = gtk_widget_accessible_get_platform_state;
8513}
8514
8515static void
8516gtk_widget_buildable_add_child (GtkBuildable *buildable,
8517 GtkBuilder *builder,
8518 GObject *child,
8519 const char *type)
8520{
8521 if (type != NULL)
8522 {
8523 GTK_BUILDER_WARN_INVALID_CHILD_TYPE (buildable, type);
8524 }
8525 if (GTK_IS_WIDGET (child))
8526 {
8527 gtk_widget_set_parent (GTK_WIDGET (child), GTK_WIDGET (buildable));
8528 }
8529 else if (GTK_IS_EVENT_CONTROLLER (child))
8530 {
8531 gtk_widget_add_controller (GTK_WIDGET (buildable), g_object_ref (GTK_EVENT_CONTROLLER (child)));
8532 }
8533 else
8534 {
8535 g_warning ("Cannot add an object of type %s to a widget of type %s",
8536 g_type_name (G_OBJECT_TYPE (child)), g_type_name (G_OBJECT_TYPE (buildable)));
8537 }
8538}
8539
8540static void
8541gtk_widget_buildable_interface_init (GtkBuildableIface *iface)
8542{
8543 quark_builder_set_id = g_quark_from_static_string (string: "gtk-builder-set-id");
8544
8545 iface->set_id = gtk_widget_buildable_set_id;
8546 iface->get_id = gtk_widget_buildable_get_id;
8547 iface->get_internal_child = gtk_widget_buildable_get_internal_child;
8548 iface->parser_finished = gtk_widget_buildable_parser_finished;
8549 iface->custom_tag_start = gtk_widget_buildable_custom_tag_start;
8550 iface->custom_tag_end = gtk_widget_buildable_custom_tag_end;
8551 iface->custom_finished = gtk_widget_buildable_custom_finished;
8552 iface->add_child = gtk_widget_buildable_add_child;
8553}
8554
8555static void
8556gtk_widget_buildable_set_id (GtkBuildable *buildable,
8557 const char *id)
8558{
8559 g_object_set_qdata_full (G_OBJECT (buildable), quark: quark_builder_set_id,
8560 data: g_strdup (str: id), destroy: g_free);
8561}
8562
8563static const char *
8564gtk_widget_buildable_get_id (GtkBuildable *buildable)
8565{
8566 return g_object_get_qdata (G_OBJECT (buildable), quark: quark_builder_set_id);
8567}
8568
8569static GObject *
8570gtk_widget_buildable_get_internal_child (GtkBuildable *buildable,
8571 GtkBuilder *builder,
8572 const char *childname)
8573{
8574 GtkWidgetClass *class;
8575 GSList *l;
8576 GType internal_child_type = 0;
8577
8578 /* Find a widget type which has declared an automated child as internal by
8579 * the name 'childname', if any.
8580 */
8581 for (class = GTK_WIDGET_GET_CLASS (buildable);
8582 GTK_IS_WIDGET_CLASS (class);
8583 class = g_type_class_peek_parent (g_class: class))
8584 {
8585 GtkWidgetTemplate *template = class->priv->template;
8586
8587 if (!template)
8588 continue;
8589
8590 for (l = template->children; l && internal_child_type == 0; l = l->next)
8591 {
8592 AutomaticChildClass *child_class = l->data;
8593
8594 if (child_class->internal_child && strcmp (s1: childname, s2: child_class->name) == 0)
8595 internal_child_type = G_OBJECT_CLASS_TYPE (class);
8596 }
8597 }
8598
8599 /* Now return the 'internal-child' from the class which declared it, note
8600 * that gtk_widget_get_template_child() an API used to access objects
8601 * which are in the private scope of a given class.
8602 */
8603 if (internal_child_type != 0)
8604 return gtk_widget_get_template_child (GTK_WIDGET (buildable), widget_type: internal_child_type, name: childname);
8605
8606 return NULL;
8607}
8608
8609static void
8610gtk_widget_buildable_parser_finished (GtkBuildable *buildable,
8611 GtkBuilder *builder)
8612{
8613}
8614
8615typedef struct
8616{
8617 GtkBuilder *builder;
8618 GSList *classes;
8619} StyleParserData;
8620
8621static void
8622style_start_element (GtkBuildableParseContext *context,
8623 const char *element_name,
8624 const char **names,
8625 const char **values,
8626 gpointer user_data,
8627 GError **error)
8628{
8629 StyleParserData *data = (StyleParserData *)user_data;
8630
8631 if (strcmp (s1: element_name, s2: "class") == 0)
8632 {
8633 const char *name;
8634
8635 if (!_gtk_builder_check_parent (builder: data->builder, context, parent_name: "style", error))
8636 return;
8637
8638 if (!g_markup_collect_attributes (element_name, attribute_names: names, attribute_values: values, error,
8639 first_type: G_MARKUP_COLLECT_STRING, first_attr: "name", &name,
8640 G_MARKUP_COLLECT_INVALID))
8641 {
8642 _gtk_builder_prefix_error (builder: data->builder, context, error);
8643 return;
8644 }
8645
8646 data->classes = g_slist_prepend (list: data->classes, data: g_strdup (str: name));
8647 }
8648 else if (strcmp (s1: element_name, s2: "style") == 0)
8649 {
8650 if (!_gtk_builder_check_parent (builder: data->builder, context, parent_name: "object", error))
8651 return;
8652
8653 if (!g_markup_collect_attributes (element_name, attribute_names: names, attribute_values: values, error,
8654 first_type: G_MARKUP_COLLECT_INVALID, NULL, NULL,
8655 G_MARKUP_COLLECT_INVALID))
8656 _gtk_builder_prefix_error (builder: data->builder, context, error);
8657 }
8658 else
8659 {
8660 _gtk_builder_error_unhandled_tag (builder: data->builder, context,
8661 object: "GtkWidget", element_name,
8662 error);
8663 }
8664}
8665
8666static const GtkBuildableParser style_parser =
8667 {
8668 style_start_element,
8669 };
8670
8671typedef struct
8672{
8673 char *name;
8674 GString *value;
8675 char *context;
8676 gboolean translatable;
8677} LayoutPropertyInfo;
8678
8679typedef struct
8680{
8681 GObject *object;
8682 GtkBuilder *builder;
8683
8684 LayoutPropertyInfo *cur_property;
8685
8686 /* SList<LayoutPropertyInfo> */
8687 GSList *properties;
8688} LayoutParserData;
8689
8690static void
8691layout_property_info_free (gpointer data)
8692{
8693 LayoutPropertyInfo *pinfo = data;
8694
8695 if (pinfo == NULL)
8696 return;
8697
8698 g_free (mem: pinfo->name);
8699 g_free (mem: pinfo->context);
8700 g_string_free (string: pinfo->value, TRUE);
8701 g_free (mem: pinfo);
8702}
8703
8704static void
8705layout_start_element (GtkBuildableParseContext *context,
8706 const char *element_name,
8707 const char **names,
8708 const char **values,
8709 gpointer user_data,
8710 GError **error)
8711{
8712 LayoutParserData *layout_data = user_data;
8713
8714 if (strcmp (s1: element_name, s2: "property") == 0)
8715 {
8716 const char *name = NULL;
8717 const char *ctx = NULL;
8718 gboolean translatable = FALSE;
8719 LayoutPropertyInfo *pinfo;
8720
8721 if (!_gtk_builder_check_parent (builder: layout_data->builder, context, parent_name: "layout", error))
8722 return;
8723
8724 if (!g_markup_collect_attributes (element_name, attribute_names: names, attribute_values: values, error,
8725 first_type: G_MARKUP_COLLECT_STRING, first_attr: "name", &name,
8726 G_MARKUP_COLLECT_BOOLEAN | G_MARKUP_COLLECT_OPTIONAL, "translatable", &translatable,
8727 G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "context", &ctx,
8728 G_MARKUP_COLLECT_INVALID))
8729 {
8730 _gtk_builder_prefix_error (builder: layout_data->builder, context, error);
8731 return;
8732 }
8733
8734 pinfo = g_new0 (LayoutPropertyInfo, 1);
8735 pinfo->name = g_strdup (str: name);
8736 pinfo->translatable = translatable;
8737 pinfo->context = g_strdup (str: ctx);
8738 pinfo->value = g_string_new (NULL);
8739
8740 layout_data->cur_property = pinfo;
8741 }
8742 else if (strcmp (s1: element_name, s2: "layout") == 0)
8743 {
8744 if (!_gtk_builder_check_parent (builder: layout_data->builder, context, parent_name: "object", error))
8745 return;
8746
8747 if (!g_markup_collect_attributes (element_name, attribute_names: names, attribute_values: values, error,
8748 first_type: G_MARKUP_COLLECT_INVALID, NULL, NULL,
8749 G_MARKUP_COLLECT_INVALID))
8750 _gtk_builder_prefix_error (builder: layout_data->builder, context, error);
8751 }
8752 else
8753 {
8754 _gtk_builder_error_unhandled_tag (builder: layout_data->builder, context,
8755 object: "GtkWidget", element_name,
8756 error);
8757 }
8758}
8759
8760static void
8761layout_text (GtkBuildableParseContext *context,
8762 const char *text,
8763 gsize text_len,
8764 gpointer user_data,
8765 GError **error)
8766{
8767 LayoutParserData *layout_data = user_data;
8768
8769 if (layout_data->cur_property != NULL)
8770 g_string_append_len (string: layout_data->cur_property->value, val: text, len: text_len);
8771}
8772
8773static void
8774layout_end_element (GtkBuildableParseContext *context,
8775 const char *element_name,
8776 gpointer user_data,
8777 GError **error)
8778{
8779 LayoutParserData *layout_data = user_data;
8780
8781 if (layout_data->cur_property != NULL)
8782 {
8783 LayoutPropertyInfo *pinfo = g_steal_pointer (&layout_data->cur_property);
8784
8785 /* Translate the string, if needed */
8786 if (pinfo->value->len != 0 && pinfo->translatable)
8787 {
8788 const char *translated;
8789 const char *domain;
8790
8791 domain = gtk_builder_get_translation_domain (builder: layout_data->builder);
8792
8793 translated = _gtk_builder_parser_translate (domain, context: pinfo->context, text: pinfo->value->str);
8794
8795 g_string_assign (string: pinfo->value, rval: translated);
8796 }
8797
8798 /* We assign all properties at the end of the `layout` section */
8799 layout_data->properties = g_slist_prepend (list: layout_data->properties, data: pinfo);
8800 }
8801}
8802
8803static const GtkBuildableParser layout_parser =
8804 {
8805 layout_start_element,
8806 layout_end_element,
8807 layout_text,
8808 };
8809
8810typedef struct
8811{
8812 char *name;
8813 GString *value;
8814 char *context;
8815 gboolean translatable;
8816} AccessibilityAttributeInfo;
8817
8818typedef struct
8819{
8820 GObject *object;
8821 GtkBuilder *builder;
8822
8823 AccessibilityAttributeInfo *cur_attribute;
8824
8825 /* SList<AccessibilityAttributeInfo> */
8826 GSList *properties;
8827 GSList *states;
8828 GSList *relations;
8829} AccessibilityParserData;
8830
8831static void
8832accessibility_attribute_info_free (gpointer data)
8833{
8834 AccessibilityAttributeInfo *pinfo = data;
8835
8836 if (pinfo == NULL)
8837 return;
8838
8839 g_free (mem: pinfo->name);
8840 g_free (mem: pinfo->context);
8841 g_string_free (string: pinfo->value, TRUE);
8842 g_free (mem: pinfo);
8843}
8844
8845static void
8846accessibility_start_element (GtkBuildableParseContext *context,
8847 const char *element_name,
8848 const char **names,
8849 const char **values,
8850 gpointer user_data,
8851 GError **error)
8852{
8853 AccessibilityParserData *accessibility_data = user_data;
8854
8855 if (strcmp (s1: element_name, s2: "property") == 0 ||
8856 strcmp (s1: element_name, s2: "relation") == 0 ||
8857 strcmp (s1: element_name, s2: "state") == 0)
8858 {
8859 const char *name = NULL;
8860 const char *ctx = NULL;
8861 gboolean translatable = FALSE;
8862 AccessibilityAttributeInfo *pinfo;
8863
8864 if (!_gtk_builder_check_parent (builder: accessibility_data->builder,
8865 context,
8866 parent_name: "accessibility",
8867 error))
8868 return;
8869
8870 if (!g_markup_collect_attributes (element_name, attribute_names: names, attribute_values: values, error,
8871 first_type: G_MARKUP_COLLECT_STRING, first_attr: "name", &name,
8872 G_MARKUP_COLLECT_BOOLEAN | G_MARKUP_COLLECT_OPTIONAL, "translatable", &translatable,
8873 G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "context", &ctx,
8874 G_MARKUP_COLLECT_INVALID))
8875 {
8876 _gtk_builder_prefix_error (builder: accessibility_data->builder, context, error);
8877 return;
8878 }
8879
8880 pinfo = g_new0 (AccessibilityAttributeInfo, 1);
8881 pinfo->name = g_strdup (str: name);
8882 pinfo->translatable = translatable;
8883 pinfo->context = g_strdup (str: ctx);
8884 pinfo->value = g_string_new (NULL);
8885
8886 accessibility_data->cur_attribute = pinfo;
8887 }
8888 else if (strcmp (s1: element_name, s2: "accessibility") == 0)
8889 {
8890 if (!_gtk_builder_check_parent (builder: accessibility_data->builder,
8891 context,
8892 parent_name: "object",
8893 error))
8894 return;
8895 }
8896 else
8897 {
8898 _gtk_builder_error_unhandled_tag (builder: accessibility_data->builder, context,
8899 object: "GtkWidget", element_name,
8900 error);
8901 }
8902}
8903
8904static void
8905accessibility_text (GtkBuildableParseContext *context,
8906 const char *text,
8907 gsize text_len,
8908 gpointer user_data,
8909 GError **error)
8910{
8911 AccessibilityParserData *accessibility_data = user_data;
8912
8913 if (accessibility_data->cur_attribute != NULL)
8914 g_string_append_len (string: accessibility_data->cur_attribute->value, val: text, len: text_len);
8915}
8916
8917static void
8918accessibility_end_element (GtkBuildableParseContext *context,
8919 const char *element_name,
8920 gpointer user_data,
8921 GError **error)
8922{
8923 AccessibilityParserData *accessibility_data = user_data;
8924
8925 if (accessibility_data->cur_attribute != NULL)
8926 {
8927 AccessibilityAttributeInfo *pinfo = g_steal_pointer (&accessibility_data->cur_attribute);
8928
8929 /* Translate the string, if needed */
8930 if (pinfo->value->len != 0 && pinfo->translatable)
8931 {
8932 const char *translated;
8933 const char *domain;
8934
8935 domain = gtk_builder_get_translation_domain (builder: accessibility_data->builder);
8936
8937 translated = _gtk_builder_parser_translate (domain, context: pinfo->context, text: pinfo->value->str);
8938
8939 g_string_assign (string: pinfo->value, rval: translated);
8940 }
8941
8942 /* We assign all properties at the end of the `accessibility` section */
8943 if (strcmp (s1: element_name, s2: "property") == 0)
8944 accessibility_data->properties = g_slist_prepend (list: accessibility_data->properties, data: pinfo);
8945 else if (strcmp (s1: element_name, s2: "relation") == 0)
8946 accessibility_data->relations = g_slist_prepend (list: accessibility_data->relations, data: pinfo);
8947 else if (strcmp (s1: element_name, s2: "state") == 0)
8948 accessibility_data->states = g_slist_prepend (list: accessibility_data->states, data: pinfo);
8949 else
8950 {
8951 _gtk_builder_error_unhandled_tag (builder: accessibility_data->builder, context,
8952 object: "GtkWidget", element_name,
8953 error);
8954 accessibility_attribute_info_free (data: pinfo);
8955 }
8956 }
8957}
8958
8959static const GtkBuildableParser accessibility_parser = {
8960 accessibility_start_element,
8961 accessibility_end_element,
8962 accessibility_text,
8963};
8964
8965static gboolean
8966gtk_widget_buildable_custom_tag_start (GtkBuildable *buildable,
8967 GtkBuilder *builder,
8968 GObject *child,
8969 const char *tagname,
8970 GtkBuildableParser *parser,
8971 gpointer *parser_data)
8972{
8973 if (strcmp (s1: tagname, s2: "style") == 0)
8974 {
8975 StyleParserData *data;
8976
8977 data = g_slice_new0 (StyleParserData);
8978 data->builder = builder;
8979
8980 *parser = style_parser;
8981 *parser_data = data;
8982
8983 return TRUE;
8984 }
8985
8986 if (strcmp (s1: tagname, s2: "layout") == 0)
8987 {
8988 LayoutParserData *data;
8989
8990 data = g_slice_new0 (LayoutParserData);
8991 data->builder = builder;
8992 data->object = (GObject *) g_object_ref (buildable);
8993
8994 *parser = layout_parser;
8995 *parser_data = data;
8996
8997 return TRUE;
8998 }
8999
9000 if (strcmp (s1: tagname, s2: "accessibility") == 0)
9001 {
9002 AccessibilityParserData *data;
9003
9004 data = g_slice_new0 (AccessibilityParserData);
9005 data->builder = builder;
9006 data->object = (GObject *) g_object_ref (buildable);
9007
9008 *parser = accessibility_parser;
9009 *parser_data = data;
9010
9011 return TRUE;
9012 }
9013
9014 return FALSE;
9015}
9016
9017static void
9018gtk_widget_buildable_custom_tag_end (GtkBuildable *buildable,
9019 GtkBuilder *builder,
9020 GObject *child,
9021 const char *tagname,
9022 gpointer data)
9023{
9024}
9025
9026static void
9027gtk_widget_buildable_finish_layout_properties (GtkWidget *widget,
9028 GtkWidget *parent,
9029 gpointer data)
9030{
9031 LayoutParserData *layout_data = data;
9032 GtkLayoutManager *layout_manager;
9033 GtkLayoutChild *layout_child;
9034 GObject *gobject;
9035 GObjectClass *gobject_class;
9036 GSList *layout_properties, *l;
9037
9038 layout_manager = gtk_widget_get_layout_manager (widget: parent);
9039 if (layout_manager == NULL)
9040 return;
9041
9042 layout_child = gtk_layout_manager_get_layout_child (manager: layout_manager, child: widget);
9043 if (layout_child == NULL)
9044 return;
9045
9046 gobject = G_OBJECT (layout_child);
9047 gobject_class = G_OBJECT_GET_CLASS (layout_child);
9048
9049 layout_properties = g_slist_reverse (list: layout_data->properties);
9050 layout_data->properties = NULL;
9051
9052 for (l = layout_properties; l != NULL; l = l->next)
9053 {
9054 LayoutPropertyInfo *pinfo = l->data;
9055 GParamSpec *pspec;
9056 GValue value = G_VALUE_INIT;
9057 GError *error = NULL;
9058
9059 pspec = g_object_class_find_property (oclass: gobject_class, property_name: pinfo->name);
9060 if (pspec == NULL)
9061 {
9062 g_warning ("Unable to find layout property “%s” for children "
9063 "of layout managers of type “%s”",
9064 pinfo->name,
9065 G_OBJECT_TYPE_NAME (layout_manager));
9066 continue;
9067 }
9068
9069 gtk_builder_value_from_string (builder: layout_data->builder,
9070 pspec,
9071 string: pinfo->value->str,
9072 value: &value,
9073 error: &error);
9074 if (error != NULL)
9075 {
9076 g_warning ("Failed to set property “%s.%s” to “%s”: %s",
9077 G_OBJECT_TYPE_NAME (layout_child),
9078 pinfo->name,
9079 pinfo->value->str,
9080 error->message);
9081 g_error_free (error);
9082 continue;
9083 }
9084
9085 g_object_set_property (object: gobject, property_name: pinfo->name, value: &value);
9086 g_value_unset (value: &value);
9087 }
9088
9089 g_slist_free_full (list: layout_properties, free_func: layout_property_info_free);
9090}
9091
9092static void
9093gtk_widget_buildable_finish_accessibility_properties (GtkWidget *widget,
9094 gpointer data)
9095{
9096 AccessibilityParserData *accessibility_data = data;
9097 GSList *attributes, *l;
9098 GtkATContext *context;
9099
9100 context = gtk_accessible_get_at_context (self: GTK_ACCESSIBLE (ptr: widget));
9101 if (context == NULL)
9102 return;
9103
9104 attributes = g_slist_reverse (list: accessibility_data->properties);
9105 accessibility_data->properties = NULL;
9106
9107 for (l = attributes; l != NULL; l = l->next)
9108 {
9109 AccessibilityAttributeInfo *pinfo = l->data;
9110 int property;
9111 GError *error = NULL;
9112 GtkAccessibleValue *value;
9113
9114 _gtk_builder_enum_from_string (type: GTK_TYPE_ACCESSIBLE_PROPERTY,
9115 string: pinfo->name,
9116 enum_value: &property,
9117 error: &error);
9118 if (error != NULL)
9119 {
9120 g_warning ("Failed to find accessible property “%s”: %s",
9121 pinfo->name,
9122 error->message);
9123 g_error_free (error);
9124 continue;
9125 }
9126
9127 value = gtk_accessible_value_parse_for_property (property,
9128 str: pinfo->value->str,
9129 len: pinfo->value->len,
9130 error: &error);
9131 if (error != NULL)
9132 {
9133 g_warning ("Failed to set accessible property “%s” to “%s”: %s",
9134 pinfo->name,
9135 pinfo->value->str,
9136 error->message);
9137 g_error_free (error);
9138 continue;
9139 }
9140
9141 gtk_at_context_set_accessible_property (self: context, property, value);
9142 gtk_accessible_value_unref (self: value);
9143 }
9144
9145 g_slist_free_full (list: attributes, free_func: accessibility_attribute_info_free);
9146
9147 attributes = g_slist_reverse (list: accessibility_data->relations);
9148 accessibility_data->relations = NULL;
9149
9150 for (l = attributes; l != NULL; l = l->next)
9151 {
9152 AccessibilityAttributeInfo *pinfo = l->data;
9153 int relation;
9154 GError *error = NULL;
9155 GtkAccessibleValue *value;
9156
9157 _gtk_builder_enum_from_string (type: GTK_TYPE_ACCESSIBLE_RELATION,
9158 string: pinfo->name,
9159 enum_value: &relation,
9160 error: &error);
9161 if (error != NULL)
9162 {
9163 g_warning ("Failed to find accessible relation “%s”: %s",
9164 pinfo->name,
9165 error->message);
9166 g_error_free (error);
9167 continue;
9168 }
9169
9170 value = gtk_accessible_value_parse_for_relation (relation,
9171 str: pinfo->value->str,
9172 len: pinfo->value->len,
9173 error: &error);
9174 if (error != NULL)
9175 {
9176 g_warning ("Failed to set accessible relation “%s” to “%s”: %s",
9177 pinfo->name,
9178 pinfo->value->str,
9179 error->message);
9180 g_error_free (error);
9181 continue;
9182 }
9183
9184 if (value == NULL)
9185 {
9186 GObject *obj = gtk_builder_get_object (builder: accessibility_data->builder,
9187 name: pinfo->value->str);
9188
9189 if (obj == NULL)
9190 {
9191 g_warning ("Failed to find accessible object “%s” for relation “%s”",
9192 pinfo->value->str,
9193 pinfo->name);
9194 continue;
9195 }
9196
9197 /* FIXME: Need to distinguish between refs and refslist types */
9198 value = gtk_reference_list_accessible_value_new (value: g_list_append (NULL, data: obj));
9199 }
9200
9201 gtk_at_context_set_accessible_relation (self: context, property: relation, value);
9202 gtk_accessible_value_unref (self: value);
9203 }
9204
9205 g_slist_free_full (list: attributes, free_func: accessibility_attribute_info_free);
9206
9207 attributes = g_slist_reverse (list: accessibility_data->states);
9208 accessibility_data->states = NULL;
9209
9210 for (l = attributes; l != NULL; l = l->next)
9211 {
9212 AccessibilityAttributeInfo *pinfo = l->data;
9213 int state;
9214 GError *error = NULL;
9215 GtkAccessibleValue *value;
9216
9217 _gtk_builder_enum_from_string (type: GTK_TYPE_ACCESSIBLE_STATE,
9218 string: pinfo->name,
9219 enum_value: &state,
9220 error: &error);
9221 if (error != NULL)
9222 {
9223 g_warning ("Failed to find accessible state “%s”: %s",
9224 pinfo->name,
9225 error->message);
9226 g_error_free (error);
9227 continue;
9228 }
9229
9230 value = gtk_accessible_value_parse_for_state (state,
9231 str: pinfo->value->str,
9232 len: pinfo->value->len,
9233 error: &error);
9234 if (error != NULL)
9235 {
9236 g_warning ("Failed to set accessible state “%s” to “%s”: %s",
9237 pinfo->name,
9238 pinfo->value->str,
9239 error->message);
9240 g_error_free (error);
9241 continue;
9242 }
9243
9244 gtk_at_context_set_accessible_state (self: context, state, value);
9245 gtk_accessible_value_unref (self: value);
9246 }
9247
9248 g_slist_free_full (list: attributes, free_func: accessibility_attribute_info_free);
9249}
9250
9251static void
9252gtk_widget_buildable_custom_finished (GtkBuildable *buildable,
9253 GtkBuilder *builder,
9254 GObject *child,
9255 const char *tagname,
9256 gpointer user_data)
9257{
9258 if (strcmp (s1: tagname, s2: "style") == 0)
9259 {
9260 StyleParserData *style_data = (StyleParserData *)user_data;
9261 GSList *l;
9262
9263 for (l = style_data->classes; l; l = l->next)
9264 gtk_widget_add_css_class (GTK_WIDGET (buildable), css_class: (const char *)l->data);
9265
9266 g_slist_free_full (list: style_data->classes, free_func: g_free);
9267 g_slice_free (StyleParserData, style_data);
9268 }
9269 else if (strcmp (s1: tagname, s2: "layout") == 0)
9270 {
9271 LayoutParserData *layout_data = (LayoutParserData *) user_data;
9272 GtkWidget *parent = _gtk_widget_get_parent (GTK_WIDGET (buildable));
9273
9274 if (parent != NULL)
9275 gtk_widget_buildable_finish_layout_properties (GTK_WIDGET (buildable),
9276 parent,
9277 data: layout_data);
9278
9279 /* Free the unapplied properties, if any */
9280 g_slist_free_full (list: layout_data->properties, free_func: layout_property_info_free);
9281 g_object_unref (object: layout_data->object);
9282 g_slice_free (LayoutParserData, layout_data);
9283 }
9284 else if (strcmp (s1: tagname, s2: "accessibility") == 0)
9285 {
9286 AccessibilityParserData *accessibility_data = user_data;
9287
9288 gtk_widget_buildable_finish_accessibility_properties (GTK_WIDGET (buildable),
9289 data: accessibility_data);
9290
9291 g_slist_free_full (list: accessibility_data->properties,
9292 free_func: accessibility_attribute_info_free);
9293 g_slist_free_full (list: accessibility_data->relations,
9294 free_func: accessibility_attribute_info_free);
9295 g_slist_free_full (list: accessibility_data->states,
9296 free_func: accessibility_attribute_info_free);
9297 g_object_unref (object: accessibility_data->object);
9298 g_slice_free (AccessibilityParserData, accessibility_data);
9299 }
9300}
9301
9302/**
9303 * gtk_widget_get_halign: (attributes org.gtk.Method.get_property=halign)
9304 * @widget: a `GtkWidget`
9305 *
9306 * Gets the horizontal alignment of @widget.
9307 *
9308 * For backwards compatibility reasons this method will never return
9309 * %GTK_ALIGN_BASELINE, but instead it will convert it to
9310 * %GTK_ALIGN_FILL. Baselines are not supported for horizontal
9311 * alignment.
9312 *
9313 * Returns: the horizontal alignment of @widget
9314 */
9315GtkAlign
9316gtk_widget_get_halign (GtkWidget *widget)
9317{
9318 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
9319
9320 g_return_val_if_fail (GTK_IS_WIDGET (widget), GTK_ALIGN_FILL);
9321
9322 if (priv->halign == GTK_ALIGN_BASELINE)
9323 return GTK_ALIGN_FILL;
9324 return priv->halign;
9325}
9326
9327/**
9328 * gtk_widget_set_halign: (attributes org.gtk.Method.set_property=halign)
9329 * @widget: a `GtkWidget`
9330 * @align: the horizontal alignment
9331 *
9332 * Sets the horizontal alignment of @widget.
9333 */
9334void
9335gtk_widget_set_halign (GtkWidget *widget,
9336 GtkAlign align)
9337{
9338 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
9339
9340 g_return_if_fail (GTK_IS_WIDGET (widget));
9341
9342 if (priv->halign == align)
9343 return;
9344
9345 priv->halign = align;
9346 gtk_widget_queue_allocate (widget);
9347 g_object_notify_by_pspec (G_OBJECT (widget), pspec: widget_props[PROP_HALIGN]);
9348}
9349
9350/**
9351 * gtk_widget_get_valign: (attributes org.gtk.Method.get_property=valign)
9352 * @widget: a `GtkWidget`
9353 *
9354 * Gets the vertical alignment of @widget.
9355 *
9356 * Returns: the vertical alignment of @widget
9357 */
9358GtkAlign
9359gtk_widget_get_valign (GtkWidget *widget)
9360{
9361 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
9362
9363 g_return_val_if_fail (GTK_IS_WIDGET (widget), GTK_ALIGN_FILL);
9364
9365 return priv->valign;
9366}
9367
9368/**
9369 * gtk_widget_set_valign: (attributes org.gtk.Method.set_property=valign)
9370 * @widget: a `GtkWidget`
9371 * @align: the vertical alignment
9372 *
9373 * Sets the vertical alignment of @widget.
9374 */
9375void
9376gtk_widget_set_valign (GtkWidget *widget,
9377 GtkAlign align)
9378{
9379 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
9380
9381 g_return_if_fail (GTK_IS_WIDGET (widget));
9382
9383 if (priv->valign == align)
9384 return;
9385
9386 priv->valign = align;
9387 gtk_widget_queue_allocate (widget);
9388 g_object_notify_by_pspec (G_OBJECT (widget), pspec: widget_props[PROP_VALIGN]);
9389}
9390
9391/**
9392 * gtk_widget_get_margin_start: (attributes org.gtk.Method.get_property=margin-start)
9393 * @widget: a `GtkWidget`
9394 *
9395 * Gets the start margin of @widget.
9396 *
9397 * Returns: The start margin of @widget
9398 */
9399int
9400gtk_widget_get_margin_start (GtkWidget *widget)
9401{
9402 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
9403
9404 g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
9405
9406 return priv->margin.left;
9407}
9408
9409/**
9410 * gtk_widget_set_margin_start: (attributes org.gtk.Method.set_property=margin-start)
9411 * @widget: a `GtkWidget`
9412 * @margin: the start margin
9413 *
9414 * Sets the start margin of @widget.
9415 */
9416void
9417gtk_widget_set_margin_start (GtkWidget *widget,
9418 int margin)
9419{
9420 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
9421
9422 g_return_if_fail (GTK_IS_WIDGET (widget));
9423 g_return_if_fail (margin <= G_MAXINT16);
9424
9425 /* We always save margin-start as .left */
9426
9427 if (priv->margin.left == margin)
9428 return;
9429
9430 priv->margin.left = margin;
9431 gtk_widget_queue_resize (widget);
9432 g_object_notify_by_pspec (G_OBJECT (widget), pspec: widget_props[PROP_MARGIN_START]);
9433}
9434
9435/**
9436 * gtk_widget_get_margin_end: (attributes org.gtk.Method.get_property=margin-end)
9437 * @widget: a `GtkWidget`
9438 *
9439 * Gets the end margin of @widget.
9440 *
9441 * Returns: The end margin of @widget
9442 */
9443int
9444gtk_widget_get_margin_end (GtkWidget *widget)
9445{
9446 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
9447
9448 g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
9449
9450 return priv->margin.right;
9451}
9452
9453/**
9454 * gtk_widget_set_margin_end: (attributes org.gtk.Method.set_property=margin-end)
9455 * @widget: a `GtkWidget`
9456 * @margin: the end margin
9457 *
9458 * Sets the end margin of @widget.
9459 */
9460void
9461gtk_widget_set_margin_end (GtkWidget *widget,
9462 int margin)
9463{
9464 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
9465
9466 g_return_if_fail (GTK_IS_WIDGET (widget));
9467 g_return_if_fail (margin <= G_MAXINT16);
9468
9469 /* We always set margin-end as .right */
9470
9471 if (priv->margin.right == margin)
9472 return;
9473
9474 priv->margin.right = margin;
9475 gtk_widget_queue_resize (widget);
9476 g_object_notify_by_pspec (G_OBJECT (widget), pspec: widget_props[PROP_MARGIN_END]);
9477}
9478
9479/**
9480 * gtk_widget_get_margin_top: (attributes org.gtk.Method.get_property=margin-top)
9481 * @widget: a `GtkWidget`
9482 *
9483 * Gets the top margin of @widget.
9484 *
9485 * Returns: The top margin of @widget
9486 */
9487int
9488gtk_widget_get_margin_top (GtkWidget *widget)
9489{
9490 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
9491
9492 g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
9493
9494 return priv->margin.top;
9495}
9496
9497/**
9498 * gtk_widget_set_margin_top: (attributes org.gtk.Method.set_property=margin-top)
9499 * @widget: a `GtkWidget`
9500 * @margin: the top margin
9501 *
9502 * Sets the top margin of @widget.
9503 */
9504void
9505gtk_widget_set_margin_top (GtkWidget *widget,
9506 int margin)
9507{
9508 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
9509
9510 g_return_if_fail (GTK_IS_WIDGET (widget));
9511 g_return_if_fail (margin <= G_MAXINT16);
9512
9513 if (priv->margin.top == margin)
9514 return;
9515
9516 priv->margin.top = margin;
9517 gtk_widget_queue_resize (widget);
9518 g_object_notify_by_pspec (G_OBJECT (widget), pspec: widget_props[PROP_MARGIN_TOP]);
9519}
9520
9521/**
9522 * gtk_widget_get_margin_bottom: (attributes org.gtk.Method.get_property=margin-bottom)
9523 * @widget: a `GtkWidget`
9524 *
9525 * Gets the bottom margin of @widget.
9526 *
9527 * Returns: The bottom margin of @widget
9528 */
9529int
9530gtk_widget_get_margin_bottom (GtkWidget *widget)
9531{
9532 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
9533
9534 g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
9535
9536 return priv->margin.bottom;
9537}
9538
9539/**
9540 * gtk_widget_set_margin_bottom: (attributes org.gtk.Method.set_property=margin-bottom)
9541 * @widget: a `GtkWidget`
9542 * @margin: the bottom margin
9543 *
9544 * Sets the bottom margin of @widget.
9545 */
9546void
9547gtk_widget_set_margin_bottom (GtkWidget *widget,
9548 int margin)
9549{
9550 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
9551
9552 g_return_if_fail (GTK_IS_WIDGET (widget));
9553 g_return_if_fail (margin <= G_MAXINT16);
9554
9555 if (priv->margin.bottom == margin)
9556 return;
9557
9558 priv->margin.bottom = margin;
9559 gtk_widget_queue_resize (widget);
9560 g_object_notify_by_pspec (G_OBJECT (widget), pspec: widget_props[PROP_MARGIN_BOTTOM]);
9561}
9562
9563/**
9564 * gtk_widget_get_clipboard:
9565 * @widget: a `GtkWidget`
9566 *
9567 * Gets the clipboard object for @widget.
9568 *
9569 * This is a utility function to get the clipboard object for the
9570 * `GdkDisplay` that @widget is using.
9571 *
9572 * Note that this function always works, even when @widget is not
9573 * realized yet.
9574 *
9575 * Returns: (transfer none): the appropriate clipboard object
9576 */
9577GdkClipboard *
9578gtk_widget_get_clipboard (GtkWidget *widget)
9579{
9580 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
9581
9582 return gdk_display_get_clipboard (display: _gtk_widget_get_display (widget));
9583}
9584
9585/**
9586 * gtk_widget_get_primary_clipboard:
9587 * @widget: a `GtkWidget`
9588 *
9589 * Gets the primary clipboard of @widget.
9590 *
9591 * This is a utility function to get the primary clipboard object
9592 * for the `GdkDisplay` that @widget is using.
9593 *
9594 * Note that this function always works, even when @widget is not
9595 * realized yet.
9596 *
9597 * Returns: (transfer none): the appropriate clipboard object
9598 **/
9599GdkClipboard *
9600gtk_widget_get_primary_clipboard (GtkWidget *widget)
9601{
9602 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
9603
9604 return gdk_display_get_primary_clipboard (display: _gtk_widget_get_display (widget));
9605}
9606
9607/**
9608 * gtk_widget_list_mnemonic_labels:
9609 * @widget: a `GtkWidget`
9610 *
9611 * Returns the widgets for which this widget is the target of a
9612 * mnemonic.
9613 *
9614 * Typically, these widgets will be labels. See, for example,
9615 * [method@Gtk.Label.set_mnemonic_widget].
9616
9617 * The widgets in the list are not individually referenced.
9618 * If you want to iterate through the list and perform actions
9619 * involving callbacks that might destroy the widgets, you
9620 * must call `g_list_foreach (result, (GFunc)g_object_ref, NULL)`
9621 * first, and then unref all the widgets afterwards.
9622
9623 * Returns: (element-type GtkWidget) (transfer container): the list
9624 * of mnemonic labels; free this list with g_list_free() when you
9625 * are done with it.
9626 */
9627GList *
9628gtk_widget_list_mnemonic_labels (GtkWidget *widget)
9629{
9630 GList *list = NULL;
9631 GSList *l;
9632
9633 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
9634
9635 for (l = g_object_get_qdata (G_OBJECT (widget), quark: quark_mnemonic_labels); l; l = l->next)
9636 list = g_list_prepend (list, data: l->data);
9637
9638 return list;
9639}
9640
9641/**
9642 * gtk_widget_add_mnemonic_label:
9643 * @widget: a `GtkWidget`
9644 * @label: a `GtkWidget` that acts as a mnemonic label for @widget
9645 *
9646 * Adds a widget to the list of mnemonic labels for this widget.
9647 *
9648 * See [method@Gtk.Widget.list_mnemonic_labels]. Note the
9649 * list of mnemonic labels for the widget is cleared when the
9650 * widget is destroyed, so the caller must make sure to update
9651 * its internal state at this point as well.
9652 */
9653void
9654gtk_widget_add_mnemonic_label (GtkWidget *widget,
9655 GtkWidget *label)
9656{
9657 GSList *old_list, *new_list;
9658 GtkAccessibleRelation relation = GTK_ACCESSIBLE_RELATION_LABELLED_BY;
9659 GValue value = G_VALUE_INIT;
9660
9661 g_return_if_fail (GTK_IS_WIDGET (widget));
9662 g_return_if_fail (GTK_IS_WIDGET (label));
9663
9664 old_list = g_object_steal_qdata (G_OBJECT (widget), quark: quark_mnemonic_labels);
9665 new_list = g_slist_prepend (list: old_list, data: label);
9666
9667 g_object_set_qdata_full (G_OBJECT (widget), quark: quark_mnemonic_labels,
9668 data: new_list, destroy: (GDestroyNotify) g_slist_free);
9669
9670 /* The ATContext takes ownership of the GList returned by list_mnemonic_labels(),
9671 * so we don't need to free it
9672 */
9673 gtk_accessible_relation_init_value (relation, value: &value);
9674 g_value_set_pointer (value: &value, v_pointer: gtk_widget_list_mnemonic_labels (widget));
9675 gtk_accessible_update_relation_value (self: GTK_ACCESSIBLE (ptr: widget), n_relations: 1, relations: &relation, values: &value);
9676 g_value_unset (value: &value);
9677}
9678
9679/**
9680 * gtk_widget_remove_mnemonic_label:
9681 * @widget: a `GtkWidget`
9682 * @label: a `GtkWidget` that was previously set as a mnemonic
9683 * label for @widget with [method@Gtk.Widget.add_mnemonic_label]
9684 *
9685 * Removes a widget from the list of mnemonic labels for this widget.
9686 *
9687 * See [method@Gtk.Widget.list_mnemonic_labels]. The widget must
9688 * have previously been added to the list with
9689 * [method@Gtk.Widget.add_mnemonic_label].
9690 */
9691void
9692gtk_widget_remove_mnemonic_label (GtkWidget *widget,
9693 GtkWidget *label)
9694{
9695 GSList *old_list, *new_list;
9696
9697 g_return_if_fail (GTK_IS_WIDGET (widget));
9698 g_return_if_fail (GTK_IS_WIDGET (label));
9699
9700 old_list = g_object_steal_qdata (G_OBJECT (widget), quark: quark_mnemonic_labels);
9701 new_list = g_slist_remove (list: old_list, data: label);
9702
9703 if (new_list)
9704 g_object_set_qdata_full (G_OBJECT (widget), quark: quark_mnemonic_labels,
9705 data: new_list, destroy: (GDestroyNotify) g_slist_free);
9706
9707 if (new_list != NULL && new_list->data != NULL)
9708 {
9709 GtkAccessibleRelation relation = GTK_ACCESSIBLE_RELATION_LABELLED_BY;
9710 GValue value = G_VALUE_INIT;
9711
9712 /* The ATContext takes ownership of the GList returned by list_mnemonic_labels(),
9713 * so we don't need to free it
9714 */
9715 gtk_accessible_relation_init_value (relation, value: &value);
9716 g_value_set_pointer (value: &value, v_pointer: gtk_widget_list_mnemonic_labels (widget));
9717 gtk_accessible_update_relation_value (self: GTK_ACCESSIBLE (ptr: widget), n_relations: 1, relations: &relation, values: &value);
9718 g_value_unset (value: &value);
9719 }
9720 else
9721 {
9722 gtk_accessible_reset_relation (self: GTK_ACCESSIBLE (ptr: widget),
9723 relation: GTK_ACCESSIBLE_RELATION_LABELLED_BY);
9724 }
9725}
9726
9727/**
9728 * gtk_widget_trigger_tooltip_query:
9729 * @widget: a `GtkWidget`
9730 *
9731 * Triggers a tooltip query on the display where the toplevel
9732 * of @widget is located.
9733 */
9734void
9735gtk_widget_trigger_tooltip_query (GtkWidget *widget)
9736{
9737 gtk_tooltip_trigger_tooltip_query (widget);
9738}
9739
9740/**
9741 * gtk_widget_set_tooltip_text: (attributes org.gtk.Method.set_property=tooltip-text)
9742 * @widget: a `GtkWidget`
9743 * @text: (nullable): the contents of the tooltip for @widget
9744 *
9745 * Sets @text as the contents of the tooltip.
9746 *
9747 * If @text contains any markup, it will be escaped.
9748 *
9749 * This function will take care of setting
9750 * [property@Gtk.Widget:has-tooltip] as a side effect,
9751 * and of the default handler for the
9752 * [signal@Gtk.Widget::query-tooltip] signal.
9753 *
9754 * See also [method@Gtk.Tooltip.set_text].
9755 */
9756void
9757gtk_widget_set_tooltip_text (GtkWidget *widget,
9758 const char *text)
9759{
9760 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
9761 GObject *object = G_OBJECT (widget);
9762 char *tooltip_text, *tooltip_markup;
9763
9764 g_return_if_fail (GTK_IS_WIDGET (widget));
9765
9766 g_object_freeze_notify (object);
9767
9768 /* Treat an empty string as a NULL string,
9769 * because an empty string would be useless for a tooltip:
9770 */
9771 if (text != NULL && *text == '\0')
9772 {
9773 tooltip_text = NULL;
9774 tooltip_markup = NULL;
9775 }
9776 else
9777 {
9778 tooltip_text = g_strdup (str: text);
9779 tooltip_markup = text != NULL ? g_markup_escape_text (text, length: -1) : NULL;
9780 }
9781
9782 g_clear_pointer (&priv->tooltip_markup, g_free);
9783 g_clear_pointer (&priv->tooltip_text, g_free);
9784
9785 priv->tooltip_text = tooltip_text;
9786 priv->tooltip_markup = tooltip_markup;
9787
9788 gtk_accessible_update_property (self: GTK_ACCESSIBLE (ptr: widget),
9789 first_property: GTK_ACCESSIBLE_PROPERTY_DESCRIPTION, priv->tooltip_text,
9790 -1);
9791
9792 gtk_widget_set_has_tooltip (widget, has_tooltip: priv->tooltip_text != NULL);
9793 if (_gtk_widget_get_visible (widget))
9794 gtk_widget_trigger_tooltip_query (widget);
9795
9796 g_object_notify_by_pspec (object, pspec: widget_props[PROP_TOOLTIP_TEXT]);
9797 g_object_notify_by_pspec (object, pspec: widget_props[PROP_TOOLTIP_MARKUP]);
9798 g_object_notify_by_pspec (object, pspec: widget_props[PROP_HAS_TOOLTIP]);
9799
9800 g_object_thaw_notify (object);
9801}
9802
9803/**
9804 * gtk_widget_get_tooltip_text: (attributes org.gtk.Method.get_property=tooltip-text)
9805 * @widget: a `GtkWidget`
9806 *
9807 * Gets the contents of the tooltip for @widget.
9808 *
9809 * If the @widget's tooltip was set using
9810 * [method@Gtk.Widget.set_tooltip_markup],
9811 * this function will return the escaped text.
9812 *
9813 * Returns: (nullable): the tooltip text
9814 */
9815const char *
9816gtk_widget_get_tooltip_text (GtkWidget *widget)
9817{
9818 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
9819
9820 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
9821
9822 return priv->tooltip_text;
9823}
9824
9825/**
9826 * gtk_widget_set_tooltip_markup: (attributes org.gtk.Method.set_property=tooltip-markup)
9827 * @widget: a `GtkWidget`
9828 * @markup: (nullable): the contents of the tooltip for @widget
9829 *
9830 * Sets @markup as the contents of the tooltip, which is marked
9831 * up with Pango markup.
9832 *
9833 * This function will take care of setting the
9834 * [property@Gtk.Widget:has-tooltip] as a side effect, and of the
9835 * default handler for the [signal@Gtk.Widget::query-tooltip] signal.
9836 *
9837 * See also [method@Gtk.Tooltip.set_markup].
9838 */
9839void
9840gtk_widget_set_tooltip_markup (GtkWidget *widget,
9841 const char *markup)
9842{
9843 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
9844 GObject *object = G_OBJECT (widget);
9845 char *tooltip_markup;
9846
9847 g_return_if_fail (GTK_IS_WIDGET (widget));
9848
9849 g_object_freeze_notify (object);
9850
9851 /* Treat an empty string as a NULL string,
9852 * because an empty string would be useless for a tooltip:
9853 */
9854 if (markup != NULL && *markup == '\0')
9855 tooltip_markup = NULL;
9856 else
9857 tooltip_markup = g_strdup (str: markup);
9858
9859 g_clear_pointer (&priv->tooltip_text, g_free);
9860 g_clear_pointer (&priv->tooltip_markup, g_free);
9861
9862 priv->tooltip_markup = tooltip_markup;
9863
9864 /* Store the tooltip without markup, as we might end up using
9865 * it for widget descriptions in the accessibility layer
9866 */
9867 if (priv->tooltip_markup != NULL)
9868 {
9869 pango_parse_markup (markup_text: priv->tooltip_markup, length: -1, accel_marker: 0, NULL,
9870 text: &priv->tooltip_text,
9871 NULL,
9872 NULL);
9873 }
9874
9875 gtk_accessible_update_property (self: GTK_ACCESSIBLE (ptr: widget),
9876 first_property: GTK_ACCESSIBLE_PROPERTY_DESCRIPTION, priv->tooltip_text,
9877 -1);
9878
9879 gtk_widget_set_has_tooltip (widget, has_tooltip: tooltip_markup != NULL);
9880 if (_gtk_widget_get_visible (widget))
9881 gtk_widget_trigger_tooltip_query (widget);
9882
9883 g_object_notify_by_pspec (object, pspec: widget_props[PROP_TOOLTIP_TEXT]);
9884 g_object_notify_by_pspec (object, pspec: widget_props[PROP_TOOLTIP_MARKUP]);
9885 g_object_notify_by_pspec (object, pspec: widget_props[PROP_HAS_TOOLTIP]);
9886
9887 g_object_thaw_notify (object);
9888}
9889
9890/**
9891 * gtk_widget_get_tooltip_markup: (attributes org.gtk.Method.get_property=tooltip-markup)
9892 * @widget: a `GtkWidget`
9893 *
9894 * Gets the contents of the tooltip for @widget.
9895 *
9896 * If the tooltip has not been set using
9897 * [method@Gtk.Widget.set_tooltip_markup], this
9898 * function returns %NULL.
9899 *
9900 * Returns: (nullable): the tooltip text
9901 */
9902const char *
9903gtk_widget_get_tooltip_markup (GtkWidget *widget)
9904{
9905 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
9906
9907 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
9908
9909 return priv->tooltip_markup;
9910}
9911
9912/**
9913 * gtk_widget_set_has_tooltip: (attributes org.gtk.Method.set_property=has-tooltip)
9914 * @widget: a `GtkWidget`
9915 * @has_tooltip: whether or not @widget has a tooltip.
9916 *
9917 * Sets the `has-tooltip` property on @widget to @has_tooltip.
9918 */
9919void
9920gtk_widget_set_has_tooltip (GtkWidget *widget,
9921 gboolean has_tooltip)
9922{
9923 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
9924
9925 g_return_if_fail (GTK_IS_WIDGET (widget));
9926
9927 has_tooltip = !!has_tooltip;
9928
9929 if (priv->has_tooltip != has_tooltip)
9930 {
9931 priv->has_tooltip = has_tooltip;
9932
9933 g_object_notify_by_pspec (G_OBJECT (widget), pspec: widget_props[PROP_HAS_TOOLTIP]);
9934 }
9935}
9936
9937/**
9938 * gtk_widget_get_has_tooltip: (attributes org.gtk.Method.get_property=has-tooltip)
9939 * @widget: a `GtkWidget`
9940 *
9941 * Returns the current value of the `has-tooltip` property.
9942 *
9943 * Returns: current value of `has-tooltip` on @widget.
9944 */
9945gboolean
9946gtk_widget_get_has_tooltip (GtkWidget *widget)
9947{
9948 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
9949
9950 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
9951
9952 return priv->has_tooltip;
9953}
9954
9955/**
9956 * gtk_widget_get_allocation:
9957 * @widget: a `GtkWidget`
9958 * @allocation: (out): a pointer to a `GtkAllocation` to copy to
9959 *
9960 * Retrieves the widget’s allocation.
9961 *
9962 * Note, when implementing a layout container: a widget’s allocation
9963 * will be its “adjusted” allocation, that is, the widget’s parent
9964 * typically calls [method@Gtk.Widget.size_allocate] with an allocation,
9965 * and that allocation is then adjusted (to handle margin
9966 * and alignment for example) before assignment to the widget.
9967 * [method@Gtk.Widget.get_allocation] returns the adjusted allocation that
9968 * was actually assigned to the widget. The adjusted allocation is
9969 * guaranteed to be completely contained within the
9970 * [method@Gtk.Widget.size_allocate] allocation, however.
9971 *
9972 * So a layout container is guaranteed that its children stay inside
9973 * the assigned bounds, but not that they have exactly the bounds the
9974 * container assigned.
9975 */
9976void
9977gtk_widget_get_allocation (GtkWidget *widget,
9978 GtkAllocation *allocation)
9979{
9980 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
9981 const graphene_rect_t *margin_rect;
9982 float dx, dy;
9983 GtkCssBoxes boxes;
9984
9985 g_return_if_fail (GTK_IS_WIDGET (widget));
9986 g_return_if_fail (allocation != NULL);
9987
9988 gtk_css_boxes_init (boxes: &boxes, widget);
9989 margin_rect = gtk_css_boxes_get_margin_rect (boxes: &boxes);
9990
9991 if (gsk_transform_get_category (priv->transform) >= GSK_TRANSFORM_CATEGORY_2D_TRANSLATE)
9992 gsk_transform_to_translate (self: priv->transform, out_dx: &dx, out_dy: &dy);
9993 else
9994 dx = dy = 0;
9995
9996 allocation->x = dx + ceil (x: margin_rect->origin.x);
9997 allocation->y = dy + ceil (x: margin_rect->origin.y);
9998 allocation->width = ceil (x: margin_rect->size.width);
9999 allocation->height = ceil (x: margin_rect->size.height);
10000}
10001
10002/**
10003 * gtk_widget_contains:
10004 * @widget: the widget to query
10005 * @x: X coordinate to test, relative to @widget's origin
10006 * @y: Y coordinate to test, relative to @widget's origin
10007 *
10008 * Tests if the point at (@x, @y) is contained in @widget.
10009 *
10010 * The coordinates for (@x, @y) must be in widget coordinates, so
10011 * (0, 0) is assumed to be the top left of @widget's content area.
10012 *
10013 * Returns: %TRUE if @widget contains (@x, @y).
10014 */
10015gboolean
10016gtk_widget_contains (GtkWidget *widget,
10017 double x,
10018 double y)
10019{
10020 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
10021
10022 if (!_gtk_widget_get_mapped (widget))
10023 return FALSE;
10024
10025 return GTK_WIDGET_GET_CLASS (widget)->contains (widget, x, y);
10026}
10027
10028/* do the checks for gtk_widget_pick that do not depend on position */
10029static gboolean
10030gtk_widget_can_be_picked (GtkWidget *widget,
10031 GtkPickFlags flags)
10032{
10033 if (!_gtk_widget_get_mapped (widget))
10034 return FALSE;
10035
10036 if (!(flags & GTK_PICK_NON_TARGETABLE) &&
10037 !gtk_widget_get_can_target (widget))
10038 return FALSE;
10039
10040 if (!(flags & GTK_PICK_INSENSITIVE) &&
10041 !_gtk_widget_is_sensitive (widget))
10042 return FALSE;
10043
10044 return TRUE;
10045}
10046
10047static GtkWidget *
10048gtk_widget_do_pick (GtkWidget *widget,
10049 double x,
10050 double y,
10051 GtkPickFlags flags)
10052{
10053 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
10054 GtkWidget *child;
10055
10056 if (priv->overflow == GTK_OVERFLOW_HIDDEN)
10057 {
10058 GtkCssBoxes boxes;
10059
10060 gtk_css_boxes_init (boxes: &boxes, widget);
10061
10062 if (!gsk_rounded_rect_contains_point (self: gtk_css_boxes_get_padding_box (boxes: &boxes),
10063 point: &GRAPHENE_POINT_INIT (x, y)))
10064 return NULL;
10065 }
10066
10067 for (child = _gtk_widget_get_last_child (widget);
10068 child;
10069 child = _gtk_widget_get_prev_sibling (widget: child))
10070 {
10071 GtkWidgetPrivate *child_priv = gtk_widget_get_instance_private (self: child);
10072 GtkWidget *picked;
10073 graphene_point3d_t res;
10074
10075 if (!gtk_widget_can_be_picked (widget: child, flags))
10076 continue;
10077
10078 if (GTK_IS_NATIVE (ptr: child))
10079 continue;
10080
10081 if (child_priv->transform)
10082 {
10083 if (gsk_transform_get_category (child_priv->transform) >= GSK_TRANSFORM_CATEGORY_2D_TRANSLATE)
10084 {
10085 graphene_point_t transformed_p;
10086
10087 gsk_transform_transform_point (self: child_priv->transform,
10088 point: &(graphene_point_t) { 0, 0 },
10089 out_point: &transformed_p);
10090
10091 graphene_point3d_init (p: &res, x: x - transformed_p.x, y: y - transformed_p.y, z: 0.);
10092 }
10093 else
10094 {
10095 GskTransform *transform;
10096 graphene_matrix_t inv;
10097 graphene_point3d_t p0, p1;
10098
10099 transform = gsk_transform_invert (self: gsk_transform_ref (self: child_priv->transform));
10100 if (transform == NULL)
10101 continue;
10102
10103 gsk_transform_to_matrix (self: transform, out_matrix: &inv);
10104 gsk_transform_unref (self: transform);
10105 graphene_point3d_init (p: &p0, x, y, z: 0);
10106 graphene_point3d_init (p: &p1, x, y, z: 1);
10107 graphene_matrix_transform_point3d (m: &inv, p: &p0, res: &p0);
10108 graphene_matrix_transform_point3d (m: &inv, p: &p1, res: &p1);
10109 if (fabs (x: p0.z - p1.z) < 1.f / 4096)
10110 continue;
10111
10112 graphene_point3d_interpolate (a: &p0, b: &p1, factor: p0.z / (p0.z - p1.z), res: &res);
10113 }
10114 }
10115 else
10116 {
10117 graphene_point3d_init (p: &res, x, y, z: 0);
10118 }
10119
10120 picked = gtk_widget_do_pick (widget: child, x: res.x, y: res.y, flags);
10121 if (picked)
10122 return picked;
10123 }
10124
10125 if (!GTK_WIDGET_GET_CLASS (widget)->contains (widget, x, y))
10126 return NULL;
10127
10128 return widget;
10129}
10130
10131/**
10132 * gtk_widget_pick:
10133 * @widget: the widget to query
10134 * @x: X coordinate to test, relative to @widget's origin
10135 * @y: Y coordinate to test, relative to @widget's origin
10136 * @flags: Flags to influence what is picked
10137 *
10138 * Finds the descendant of @widget closest to the point (@x, @y).
10139 *
10140 * The point must be given in widget coordinates, so (0, 0) is assumed
10141 * to be the top left of @widget's content area.
10142 *
10143 * Usually widgets will return %NULL if the given coordinate is not
10144 * contained in @widget checked via [method@Gtk.Widget.contains].
10145 * Otherwise they will recursively try to find a child that does
10146 * not return %NULL. Widgets are however free to customize their
10147 * picking algorithm.
10148 *
10149 * This function is used on the toplevel to determine the widget
10150 * below the mouse cursor for purposes of hover highlighting and
10151 * delivering events.
10152 *
10153 * Returns: (nullable) (transfer none): The widget descendant at
10154 * the given point
10155 */
10156GtkWidget *
10157gtk_widget_pick (GtkWidget *widget,
10158 double x,
10159 double y,
10160 GtkPickFlags flags)
10161{
10162 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
10163
10164 if (!gtk_widget_can_be_picked (widget, flags))
10165 return NULL;
10166
10167 return gtk_widget_do_pick (widget, x, y, flags);
10168}
10169
10170/**
10171 * gtk_widget_compute_transform:
10172 * @widget: a `GtkWidget`
10173 * @target: the target widget that the matrix will transform to
10174 * @out_transform: (out caller-allocates): location to
10175 * store the final transformation
10176 *
10177 * Computes a matrix suitable to describe a transformation from
10178 * @widget's coordinate system into @target's coordinate system.
10179 *
10180 * The transform can not be computed in certain cases, for example
10181 * when @widget and @target do not share a common ancestor. In that
10182 * case @out_transform gets set to the identity matrix.
10183 *
10184 * Returns: %TRUE if the transform could be computed, %FALSE otherwise
10185 */
10186gboolean
10187gtk_widget_compute_transform (GtkWidget *widget,
10188 GtkWidget *target,
10189 graphene_matrix_t *out_transform)
10190{
10191 GtkWidget *ancestor, *iter;
10192 graphene_matrix_t transform, inverse, tmp;
10193
10194 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
10195 g_return_val_if_fail (GTK_IS_WIDGET (target), FALSE);
10196 g_return_val_if_fail (out_transform != NULL, FALSE);
10197
10198 if (widget->priv->root != target->priv->root)
10199 return FALSE;
10200
10201 /* optimization for common case: parent wants coordinates of a direct child */
10202 if (target == widget->priv->parent)
10203 {
10204 gsk_transform_to_matrix (self: widget->priv->transform, out_matrix: out_transform);
10205 return TRUE;
10206 }
10207
10208 ancestor = gtk_widget_common_ancestor (widget_a: widget, widget_b: target);
10209 if (ancestor == NULL)
10210 {
10211 graphene_matrix_init_identity (m: out_transform);
10212 return FALSE;
10213 }
10214
10215 graphene_matrix_init_identity (m: &transform);
10216 for (iter = widget; iter != ancestor; iter = iter->priv->parent)
10217 {
10218 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: iter);
10219 gsk_transform_to_matrix (self: priv->transform, out_matrix: &tmp);
10220
10221 graphene_matrix_multiply (a: &transform, b: &tmp, res: &transform);
10222 }
10223
10224 /* optimization for common case: parent wants coordinates of a non-direct child */
10225 if (ancestor == target)
10226 {
10227 graphene_matrix_init_from_matrix (m: out_transform, src: &transform);
10228 return TRUE;
10229 }
10230
10231 graphene_matrix_init_identity (m: &inverse);
10232 for (iter = target; iter != ancestor; iter = iter->priv->parent)
10233 {
10234 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: iter);
10235 gsk_transform_to_matrix (self: priv->transform, out_matrix: &tmp);
10236
10237 graphene_matrix_multiply (a: &inverse, b: &tmp, res: &inverse);
10238 }
10239 if (!graphene_matrix_inverse (m: &inverse, res: &inverse))
10240 {
10241 graphene_matrix_init_identity (m: out_transform);
10242 return FALSE;
10243 }
10244
10245 graphene_matrix_multiply (a: &transform, b: &inverse, res: out_transform);
10246
10247 return TRUE;
10248}
10249
10250/**
10251 * gtk_widget_compute_bounds:
10252 * @widget: the `GtkWidget` to query
10253 * @target: the `GtkWidget`
10254 * @out_bounds: (out caller-allocates): the rectangle taking the bounds
10255 *
10256 * Computes the bounds for @widget in the coordinate space of @target.
10257 *
10258 * FIXME: Explain what "bounds" are.
10259 *
10260 * If the operation is successful, %TRUE is returned. If @widget has no
10261 * bounds or the bounds cannot be expressed in @target's coordinate space
10262 * (for example if both widgets are in different windows), %FALSE is
10263 * returned and @bounds is set to the zero rectangle.
10264 *
10265 * It is valid for @widget and @target to be the same widget.
10266 *
10267 * Returns: %TRUE if the bounds could be computed
10268 */
10269gboolean
10270gtk_widget_compute_bounds (GtkWidget *widget,
10271 GtkWidget *target,
10272 graphene_rect_t *out_bounds)
10273{
10274 graphene_matrix_t transform;
10275 GtkCssBoxes boxes;
10276
10277 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
10278 g_return_val_if_fail (GTK_IS_WIDGET (target), FALSE);
10279 g_return_val_if_fail (out_bounds != NULL, FALSE);
10280
10281 if (!gtk_widget_compute_transform (widget, target, out_transform: &transform))
10282 {
10283 graphene_rect_init_from_rect (r: out_bounds, src: graphene_rect_zero ());
10284 return FALSE;
10285 }
10286
10287 gtk_css_boxes_init (boxes: &boxes, widget);
10288 gsk_matrix_transform_bounds (m: &transform,
10289 r: gtk_css_boxes_get_border_rect (boxes: &boxes),
10290 res: out_bounds);
10291
10292 return TRUE;
10293}
10294
10295/**
10296 * gtk_widget_get_allocated_width:
10297 * @widget: the widget to query
10298 *
10299 * Returns the width that has currently been allocated to @widget.
10300 *
10301 * Returns: the width of the @widget
10302 */
10303int
10304gtk_widget_get_allocated_width (GtkWidget *widget)
10305{
10306 GtkCssBoxes boxes;
10307
10308 g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
10309
10310 gtk_css_boxes_init (boxes: &boxes, widget);
10311
10312 return gtk_css_boxes_get_margin_rect (boxes: &boxes)->size.width;
10313}
10314
10315/**
10316 * gtk_widget_get_allocated_height:
10317 * @widget: the widget to query
10318 *
10319 * Returns the height that has currently been allocated to @widget.
10320 *
10321 * Returns: the height of the @widget
10322 */
10323int
10324gtk_widget_get_allocated_height (GtkWidget *widget)
10325{
10326 GtkCssBoxes boxes;
10327
10328 g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
10329
10330 gtk_css_boxes_init (boxes: &boxes, widget);
10331
10332 return gtk_css_boxes_get_margin_rect (boxes: &boxes)->size.height;
10333}
10334
10335/**
10336 * gtk_widget_get_allocated_baseline:
10337 * @widget: the widget to query
10338 *
10339 * Returns the baseline that has currently been allocated to @widget.
10340 *
10341 * This function is intended to be used when implementing handlers
10342 * for the `GtkWidget`Class.snapshot() function, and when allocating
10343 * child widgets in `GtkWidget`Class.size_allocate().
10344 *
10345 * Returns: the baseline of the @widget, or -1 if none
10346 */
10347int
10348gtk_widget_get_allocated_baseline (GtkWidget *widget)
10349{
10350 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
10351 GtkCssStyle *style;
10352 GtkBorder margin, border, padding;
10353
10354 g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
10355
10356 if (priv->baseline == -1)
10357 return -1;
10358
10359 style = gtk_css_node_get_style (cssnode: priv->cssnode);
10360 get_box_margin (style, margin: &margin);
10361 get_box_border (style, border: &border);
10362 get_box_padding (style, border: &padding);
10363
10364 return priv->baseline - margin.top - border.top - padding.top;
10365}
10366
10367/**
10368 * gtk_widget_set_opacity: (attributes org.gtk.Method.set_property=opacity)
10369 * @widget: a `GtkWidget`
10370 * @opacity: desired opacity, between 0 and 1
10371 *
10372 * Request the @widget to be rendered partially transparent.
10373 *
10374 * An opacity of 0 is fully transparent and an opacity of 1
10375 * is fully opaque.
10376 *
10377 * Opacity works on both toplevel widgets and child widgets, although
10378 * there are some limitations: For toplevel widgets, applying opacity
10379 * depends on the capabilities of the windowing system. On X11, this
10380 * has any effect only on X displays with a compositing manager,
10381 * see gdk_display_is_composited(). On Windows and Wayland it should
10382 * always work, although setting a window’s opacity after the window
10383 * has been shown may cause some flicker.
10384 *
10385 * Note that the opacity is inherited through inclusion — if you set
10386 * a toplevel to be partially translucent, all of its content will
10387 * appear translucent, since it is ultimatively rendered on that
10388 * toplevel. The opacity value itself is not inherited by child
10389 * widgets (since that would make widgets deeper in the hierarchy
10390 * progressively more translucent). As a consequence, [class@Gtk.Popover]s
10391 * and other [iface@Gtk.Native] widgets with their own surface will use their
10392 * own opacity value, and thus by default appear non-translucent,
10393 * even if they are attached to a toplevel that is translucent.
10394 */
10395void
10396gtk_widget_set_opacity (GtkWidget *widget,
10397 double opacity)
10398{
10399 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
10400 guint8 alpha;
10401
10402 g_return_if_fail (GTK_IS_WIDGET (widget));
10403
10404 opacity = CLAMP (opacity, 0.0, 1.0);
10405
10406 alpha = round (x: opacity * 255);
10407
10408 if (alpha == priv->user_alpha)
10409 return;
10410
10411 priv->user_alpha = alpha;
10412
10413 gtk_widget_queue_draw (widget);
10414
10415 g_object_notify_by_pspec (G_OBJECT (widget), pspec: widget_props[PROP_OPACITY]);
10416}
10417
10418/**
10419 * gtk_widget_get_opacity: (attributes org.gtk.Method.get_property=opacity)
10420 * @widget: a `GtkWidget`
10421 *
10422 * #Fetches the requested opacity for this widget.
10423 *
10424 * See [method@Gtk.Widget.set_opacity].
10425 *
10426 * Returns: the requested opacity for this widget.
10427 */
10428double
10429gtk_widget_get_opacity (GtkWidget *widget)
10430{
10431 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
10432
10433 g_return_val_if_fail (GTK_IS_WIDGET (widget), 0.0);
10434
10435 return priv->user_alpha / 255.0;
10436}
10437
10438/**
10439 * gtk_widget_set_overflow: (attributes org.gtk.Method.set_property=overflow)
10440 * @widget: a `GtkWidget`
10441 * @overflow: desired overflow
10442 *
10443 * Sets how @widget treats content that is drawn outside the
10444 * widget's content area.
10445 *
10446 * See the definition of [enum@Gtk.Overflow] for details.
10447 *
10448 * This setting is provided for widget implementations and
10449 * should not be used by application code.
10450 *
10451 * The default value is %GTK_OVERFLOW_VISIBLE.
10452 */
10453void
10454gtk_widget_set_overflow (GtkWidget *widget,
10455 GtkOverflow overflow)
10456{
10457 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
10458
10459 g_return_if_fail (GTK_IS_WIDGET (widget));
10460
10461 if (priv->overflow == overflow)
10462 return;
10463
10464 priv->overflow = overflow;
10465
10466 gtk_widget_queue_draw (widget);
10467
10468 g_object_notify_by_pspec (G_OBJECT (widget), pspec: widget_props[PROP_OVERFLOW]);
10469}
10470
10471/**
10472 * gtk_widget_get_overflow: (attributes org.gtk.Method.get_property=overflow)
10473 * @widget: a `GtkWidget`
10474 *
10475 * Returns the widgets overflow value.
10476 *
10477 * Returns: The widget's overflow.
10478 **/
10479GtkOverflow
10480gtk_widget_get_overflow (GtkWidget *widget)
10481{
10482 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
10483
10484 g_return_val_if_fail (GTK_IS_WIDGET (widget), GTK_OVERFLOW_VISIBLE);
10485
10486 return priv->overflow;
10487}
10488
10489void
10490gtk_widget_set_has_focus (GtkWidget *widget,
10491 gboolean has_focus)
10492{
10493 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
10494
10495 if (priv->has_focus == has_focus)
10496 return;
10497
10498 priv->has_focus = has_focus;
10499
10500 gtk_accessible_platform_changed (self: GTK_ACCESSIBLE (ptr: widget), change: GTK_ACCESSIBLE_PLATFORM_CHANGE_FOCUSED);
10501
10502 g_object_notify_by_pspec (G_OBJECT (widget), pspec: widget_props[PROP_HAS_FOCUS]);
10503}
10504
10505/**
10506 * gtk_widget_in_destruction:
10507 * @widget: a `GtkWidget`
10508 *
10509 * Returns whether the widget is currently being destroyed.
10510 *
10511 * This information can sometimes be used to avoid doing
10512 * unnecessary work.
10513 *
10514 * Returns: %TRUE if @widget is being destroyed
10515 */
10516gboolean
10517gtk_widget_in_destruction (GtkWidget *widget)
10518{
10519 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
10520
10521 return priv->in_destruction;
10522}
10523
10524gboolean
10525_gtk_widget_get_alloc_needed (GtkWidget *widget)
10526{
10527 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
10528
10529 return priv->alloc_needed;
10530}
10531
10532static void
10533gtk_widget_set_alloc_needed (GtkWidget *widget)
10534{
10535 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
10536
10537 priv->alloc_needed = TRUE;
10538
10539 do
10540 {
10541 if (priv->alloc_needed_on_child)
10542 break;
10543
10544 priv->alloc_needed_on_child = TRUE;
10545
10546 if (!priv->visible)
10547 break;
10548
10549 if (GTK_IS_NATIVE (ptr: widget))
10550 gtk_native_queue_relayout (native: GTK_NATIVE (ptr: widget));
10551
10552 widget = priv->parent;
10553 if (widget == NULL)
10554 break;
10555
10556 priv = widget->priv;
10557 }
10558 while (TRUE);
10559}
10560
10561gboolean
10562gtk_widget_needs_allocate (GtkWidget *widget)
10563{
10564 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
10565
10566 if (!priv->visible || !priv->child_visible)
10567 return FALSE;
10568
10569 if (priv->resize_needed || priv->alloc_needed || priv->alloc_needed_on_child)
10570 return TRUE;
10571
10572 return FALSE;
10573}
10574
10575void
10576gtk_widget_ensure_allocate (GtkWidget *widget)
10577{
10578 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
10579
10580 if (!gtk_widget_needs_allocate (widget))
10581 return;
10582
10583 gtk_widget_ensure_resize (widget);
10584
10585 /* This code assumes that we only reach here if the previous
10586 * allocation is still valid (ie no resize was queued).
10587 * If that wasn't true, the parent would have taken care of
10588 * things.
10589 */
10590 if (priv->alloc_needed)
10591 {
10592 gtk_widget_allocate (widget,
10593 width: priv->allocated_width,
10594 height: priv->allocated_height,
10595 baseline: priv->allocated_size_baseline,
10596 transform: gsk_transform_ref (self: priv->allocated_transform));
10597 }
10598 else if (priv->alloc_needed_on_child)
10599 {
10600 GtkWidget *child;
10601
10602 priv->alloc_needed_on_child = FALSE;
10603
10604 for (child = _gtk_widget_get_first_child (widget);
10605 child != NULL;
10606 child = _gtk_widget_get_next_sibling (widget: child))
10607 {
10608 gtk_widget_ensure_allocate (widget: child);
10609 }
10610 }
10611}
10612
10613void
10614gtk_widget_ensure_resize (GtkWidget *widget)
10615{
10616 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
10617
10618 if (!priv->resize_needed)
10619 return;
10620
10621 priv->resize_needed = FALSE;
10622}
10623
10624void
10625_gtk_widget_add_sizegroup (GtkWidget *widget,
10626 gpointer group)
10627{
10628 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
10629 GSList *groups;
10630
10631 groups = g_object_get_qdata (G_OBJECT (widget), quark: quark_size_groups);
10632 groups = g_slist_prepend (list: groups, data: group);
10633 g_object_set_qdata (G_OBJECT (widget), quark: quark_size_groups, data: groups);
10634
10635 priv->have_size_groups = TRUE;
10636}
10637
10638void
10639_gtk_widget_remove_sizegroup (GtkWidget *widget,
10640 gpointer group)
10641{
10642 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
10643 GSList *groups;
10644
10645 groups = g_object_get_qdata (G_OBJECT (widget), quark: quark_size_groups);
10646 groups = g_slist_remove (list: groups, data: group);
10647 g_object_set_qdata (G_OBJECT (widget), quark: quark_size_groups, data: groups);
10648
10649 priv->have_size_groups = groups != NULL;
10650}
10651
10652GSList *
10653_gtk_widget_get_sizegroups (GtkWidget *widget)
10654{
10655 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
10656
10657 if (priv->have_size_groups)
10658 return g_object_get_qdata (G_OBJECT (widget), quark: quark_size_groups);
10659
10660 return NULL;
10661}
10662
10663/**
10664 * gtk_widget_class_set_css_name:
10665 * @widget_class: class to set the name on
10666 * @name: name to use
10667 *
10668 * Sets the name to be used for CSS matching of widgets.
10669 *
10670 * If this function is not called for a given class, the name
10671 * set on the parent class is used. By default, `GtkWidget`
10672 * uses the name "widget".
10673 */
10674void
10675gtk_widget_class_set_css_name (GtkWidgetClass *widget_class,
10676 const char *name)
10677{
10678 GtkWidgetClassPrivate *priv;
10679
10680 g_return_if_fail (GTK_IS_WIDGET_CLASS (widget_class));
10681 g_return_if_fail (name != NULL);
10682
10683 priv = widget_class->priv;
10684
10685 priv->css_name = g_quark_from_string (string: name);
10686}
10687
10688/**
10689 * gtk_widget_class_get_css_name:
10690 * @widget_class: class to set the name on
10691 *
10692 * Gets the name used by this class for matching in CSS code.
10693 *
10694 * See [method@Gtk.WidgetClass.set_css_name] for details.
10695 *
10696 * Returns: the CSS name of the given class
10697 */
10698const char *
10699gtk_widget_class_get_css_name (GtkWidgetClass *widget_class)
10700{
10701 g_return_val_if_fail (GTK_IS_WIDGET_CLASS (widget_class), NULL);
10702
10703 return g_quark_to_string (quark: widget_class->priv->css_name);
10704}
10705
10706void
10707gtk_widget_css_changed (GtkWidget *widget,
10708 GtkCssStyleChange *change)
10709{
10710 GTK_WIDGET_GET_CLASS (widget)->css_changed (widget, change);
10711}
10712
10713void
10714gtk_widget_system_setting_changed (GtkWidget *widget,
10715 GtkSystemSetting setting)
10716{
10717 GTK_WIDGET_GET_CLASS (widget)->system_setting_changed (widget, setting);
10718}
10719
10720void
10721gtk_system_setting_changed (GdkDisplay *display,
10722 GtkSystemSetting setting)
10723{
10724 GList *list, *toplevels;
10725
10726 toplevels = gtk_window_list_toplevels ();
10727 g_list_foreach (list: toplevels, func: (GFunc) g_object_ref, NULL);
10728
10729 for (list = toplevels; list; list = list->next)
10730 {
10731 if (gtk_widget_get_display (widget: list->data) == display)
10732 gtk_widget_system_setting_changed (widget: list->data, setting);
10733 g_object_unref (object: list->data);
10734 }
10735
10736 g_list_free (list: toplevels);
10737}
10738
10739GtkCssNode *
10740gtk_widget_get_css_node (GtkWidget *widget)
10741{
10742 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
10743
10744 return priv->cssnode;
10745}
10746
10747GtkStyleContext *
10748_gtk_widget_peek_style_context (GtkWidget *widget)
10749{
10750 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
10751
10752 return priv->context;
10753}
10754
10755
10756/**
10757 * gtk_widget_get_style_context:
10758 * @widget: a `GtkWidget`
10759 *
10760 * Returns the style context associated to @widget.
10761 *
10762 * The returned object is guaranteed to be the same
10763 * for the lifetime of @widget.
10764 *
10765 * Returns: (transfer none): the widgets `GtkStyleContext`
10766 */
10767GtkStyleContext *
10768gtk_widget_get_style_context (GtkWidget *widget)
10769{
10770 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
10771
10772 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
10773
10774 if (G_UNLIKELY (priv->context == NULL))
10775 {
10776 GdkDisplay *display;
10777
10778 priv->context = gtk_style_context_new_for_node (node: priv->cssnode);
10779
10780 gtk_style_context_set_scale (context: priv->context, scale: gtk_widget_get_scale_factor (widget));
10781
10782 display = _gtk_widget_get_display (widget);
10783 if (display)
10784 gtk_style_context_set_display (context: priv->context, display);
10785 }
10786
10787 return priv->context;
10788}
10789
10790static GtkActionMuxer *
10791gtk_widget_get_parent_muxer (GtkWidget *widget,
10792 gboolean create)
10793{
10794 GtkWidget *parent;
10795
10796 if (GTK_IS_WINDOW (widget))
10797 return gtk_application_get_parent_muxer_for_window (window: (GtkWindow *)widget);
10798
10799 parent = _gtk_widget_get_parent (widget);
10800
10801 if (parent)
10802 return _gtk_widget_get_action_muxer (widget: parent, create);
10803
10804 return NULL;
10805}
10806
10807void
10808_gtk_widget_update_parent_muxer (GtkWidget *widget)
10809{
10810 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
10811 GtkWidget *child;
10812
10813 if (priv->muxer == NULL)
10814 return;
10815
10816 gtk_action_muxer_set_parent (muxer: priv->muxer,
10817 parent: gtk_widget_get_parent_muxer (widget, FALSE));
10818 for (child = gtk_widget_get_first_child (widget);
10819 child != NULL;
10820 child = gtk_widget_get_next_sibling (widget: child))
10821 _gtk_widget_update_parent_muxer (widget: child);
10822}
10823
10824GtkActionMuxer *
10825_gtk_widget_get_action_muxer (GtkWidget *widget,
10826 gboolean create)
10827{
10828 GtkWidgetClass *widget_class = GTK_WIDGET_GET_CLASS (widget);
10829 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
10830
10831 if (priv->muxer)
10832 return priv->muxer;
10833
10834 if (create || widget_class->priv->actions)
10835 {
10836 priv->muxer = gtk_action_muxer_new (widget);
10837 _gtk_widget_update_parent_muxer (widget);
10838
10839 return priv->muxer;
10840 }
10841 else
10842 return gtk_widget_get_parent_muxer (widget, FALSE);
10843}
10844
10845/**
10846 * gtk_widget_insert_action_group:
10847 * @widget: a `GtkWidget`
10848 * @name: the prefix for actions in @group
10849 * @group: (nullable): a `GActionGroup`, or %NULL to remove
10850 * the previously inserted group for @name
10851 *
10852 * Inserts @group into @widget.
10853 *
10854 * Children of @widget that implement [iface@Gtk.Actionable] can
10855 * then be associated with actions in @group by setting their
10856 * “action-name” to @prefix.`action-name`.
10857 *
10858 * Note that inheritance is defined for individual actions. I.e.
10859 * even if you insert a group with prefix @prefix, actions with
10860 * the same prefix will still be inherited from the parent, unless
10861 * the group contains an action with the same name.
10862 *
10863 * If @group is %NULL, a previously inserted group for @name is
10864 * removed from @widget.
10865 */
10866void
10867gtk_widget_insert_action_group (GtkWidget *widget,
10868 const char *name,
10869 GActionGroup *group)
10870{
10871 GtkActionMuxer *muxer;
10872
10873 g_return_if_fail (GTK_IS_WIDGET (widget));
10874 g_return_if_fail (name != NULL);
10875
10876 muxer = _gtk_widget_get_action_muxer (widget, TRUE);
10877
10878 if (group)
10879 gtk_action_muxer_insert (muxer, prefix: name, action_group: group);
10880 else
10881 gtk_action_muxer_remove (muxer, prefix: name);
10882}
10883
10884/****************************************************************
10885 * GtkBuilder automated templates *
10886 ****************************************************************/
10887static AutomaticChildClass *
10888template_child_class_new (const char *name,
10889 gboolean internal_child,
10890 gssize offset)
10891{
10892 AutomaticChildClass *child_class = g_slice_new0 (AutomaticChildClass);
10893
10894 child_class->name = g_strdup (str: name);
10895 child_class->internal_child = internal_child;
10896 child_class->offset = offset;
10897
10898 return child_class;
10899}
10900
10901static GHashTable *
10902get_auto_child_hash (GtkWidget *widget,
10903 GType type,
10904 gboolean create)
10905{
10906 GHashTable *auto_children;
10907 GHashTable *auto_child_hash;
10908
10909 auto_children = (GHashTable *)g_object_get_qdata (G_OBJECT (widget), quark: quark_auto_children);
10910 if (auto_children == NULL)
10911 {
10912 if (!create)
10913 return NULL;
10914
10915 auto_children = g_hash_table_new_full (hash_func: g_direct_hash,
10916 NULL,
10917 NULL, value_destroy_func: (GDestroyNotify)g_hash_table_destroy);
10918 g_object_set_qdata_full (G_OBJECT (widget),
10919 quark: quark_auto_children,
10920 data: auto_children,
10921 destroy: (GDestroyNotify)g_hash_table_destroy);
10922 }
10923
10924 auto_child_hash =
10925 g_hash_table_lookup (hash_table: auto_children, GSIZE_TO_POINTER (type));
10926
10927 if (!auto_child_hash && create)
10928 {
10929 auto_child_hash = g_hash_table_new_full (hash_func: g_str_hash,
10930 key_equal_func: g_str_equal,
10931 NULL,
10932 value_destroy_func: (GDestroyNotify)g_object_unref);
10933
10934 g_hash_table_insert (hash_table: auto_children,
10935 GSIZE_TO_POINTER (type),
10936 value: auto_child_hash);
10937 }
10938
10939 return auto_child_hash;
10940}
10941
10942/**
10943 * gtk_widget_init_template:
10944 * @widget: a `GtkWidget`
10945 *
10946 * Creates and initializes child widgets defined in templates.
10947 *
10948 * This function must be called in the instance initializer
10949 * for any class which assigned itself a template using
10950 * [method@Gtk.WidgetClass.set_template].
10951 *
10952 * It is important to call this function in the instance initializer
10953 * of a `GtkWidget` subclass and not in `GObject.constructed()` or
10954 * `GObject.constructor()` for two reasons:
10955 *
10956 * - derived widgets will assume that the composite widgets
10957 * defined by its parent classes have been created in their
10958 * relative instance initializers
10959 * - when calling `g_object_new()` on a widget with composite templates,
10960 * it’s important to build the composite widgets before the construct
10961 * properties are set. Properties passed to `g_object_new()` should
10962 * take precedence over properties set in the private template XML
10963 *
10964 * A good rule of thumb is to call this function as the first thing in
10965 * an instance initialization function.
10966 */
10967void
10968gtk_widget_init_template (GtkWidget *widget)
10969{
10970 GtkWidgetTemplate *template;
10971 GtkBuilder *builder;
10972 GError *error = NULL;
10973 GObject *object;
10974 GSList *l;
10975 GType class_type;
10976
10977 g_return_if_fail (GTK_IS_WIDGET (widget));
10978
10979 object = G_OBJECT (widget);
10980 class_type = G_OBJECT_TYPE (widget);
10981
10982 template = GTK_WIDGET_GET_CLASS (widget)->priv->template;
10983 g_return_if_fail (template != NULL);
10984
10985 builder = gtk_builder_new ();
10986
10987 if (template->scope)
10988 gtk_builder_set_scope (builder, scope: template->scope);
10989
10990 gtk_builder_set_current_object (builder, current_object: object);
10991
10992 /* This will build the template XML as children to the widget instance, also it
10993 * will validate that the template is created for the correct GType and assert that
10994 * there is no infinite recursion.
10995 */
10996 if (!gtk_builder_extend_with_template (builder, object, template_type: class_type,
10997 buffer: (const char *)g_bytes_get_data (bytes: template->data, NULL),
10998 length: g_bytes_get_size (bytes: template->data),
10999 error: &error))
11000 {
11001 /* This should never happen, if the template XML cannot be built
11002 * then it is a critical programming error.
11003 */
11004 g_critical ("Error building template class '%s' for an instance of type '%s': %s",
11005 g_type_name (class_type), G_OBJECT_TYPE_NAME (object), error->message);
11006 g_error_free (error);
11007 goto out;
11008 }
11009
11010 /* Build the automatic child data */
11011 for (l = template->children; l; l = l->next)
11012 {
11013 AutomaticChildClass *child_class = l->data;
11014 GHashTable *auto_child_hash;
11015 GObject *child;
11016
11017 /* This will setup the pointer of an automated child, and cause
11018 * it to be available in any GtkBuildable.get_internal_child()
11019 * invocations which may follow by reference in child classes. */
11020 child = gtk_builder_get_object (builder, name: child_class->name);
11021 if (!child)
11022 {
11023 g_critical ("Unable to retrieve child object '%s' from class "
11024 "template for type '%s' while building a '%s'",
11025 child_class->name, g_type_name (class_type), G_OBJECT_TYPE_NAME (widget));
11026 goto out;
11027 }
11028
11029 /* Insert into the hash so that it can be fetched with
11030 * gtk_widget_get_template_child() and also in automated
11031 * implementations of GtkBuildable.get_internal_child() */
11032 auto_child_hash = get_auto_child_hash (widget, type: class_type, TRUE);
11033 g_hash_table_insert (hash_table: auto_child_hash, key: child_class->name, g_object_ref (child));
11034
11035 if (child_class->offset != 0)
11036 {
11037 gpointer field_p;
11038
11039 /* Assign 'object' to the specified offset in the instance (or private) data */
11040 field_p = G_STRUCT_MEMBER_P (widget, child_class->offset);
11041 (* (gpointer *) field_p) = child;
11042 }
11043 }
11044
11045out:
11046 g_object_unref (object: builder);
11047}
11048
11049/**
11050 * gtk_widget_class_set_template:
11051 * @widget_class: A `GtkWidgetClass`
11052 * @template_bytes: A `GBytes` holding the `GtkBuilder` XML
11053 *
11054 * This should be called at class initialization time to specify
11055 * the `GtkBuilder` XML to be used to extend a widget.
11056 *
11057 * For convenience, [method@Gtk.WidgetClass.set_template_from_resource]
11058 * is also provided.
11059 *
11060 * Note that any class that installs templates must call
11061 * [method@Gtk.Widget.init_template] in the widget’s instance initializer.
11062 */
11063void
11064gtk_widget_class_set_template (GtkWidgetClass *widget_class,
11065 GBytes *template_bytes)
11066{
11067 GError *error = NULL;
11068 GBytes *data = NULL;
11069 gconstpointer bytes_data;
11070 gsize bytes_size;
11071
11072 g_return_if_fail (GTK_IS_WIDGET_CLASS (widget_class));
11073 g_return_if_fail (widget_class->priv->template == NULL);
11074 g_return_if_fail (template_bytes != NULL);
11075
11076 widget_class->priv->template = g_slice_new0 (GtkWidgetTemplate);
11077 bytes_data = g_bytes_get_data (bytes: template_bytes, size: &bytes_size);
11078
11079 if (_gtk_buildable_parser_is_precompiled (data: bytes_data, data_len: bytes_size))
11080 {
11081 widget_class->priv->template->data = g_bytes_ref (bytes: template_bytes);
11082 return;
11083 }
11084
11085 data = _gtk_buildable_parser_precompile (text: bytes_data, text_len: bytes_size, error: &error);
11086 if (data == NULL)
11087 {
11088 g_warning ("Failed to precompile template for class %s: %s", G_OBJECT_CLASS_NAME (widget_class), error->message);
11089 g_error_free (error);
11090 return;
11091 }
11092
11093 widget_class->priv->template->data = data;
11094}
11095
11096/**
11097 * gtk_widget_class_set_template_from_resource:
11098 * @widget_class: A `GtkWidgetClass`
11099 * @resource_name: The name of the resource to load the template from
11100 *
11101 * A convenience function that calls [method@Gtk.WidgetClass.set_template]
11102 * with the contents of a `GResource`.
11103 *
11104 * Note that any class that installs templates must call
11105 * [method@Gtk.Widget.init_template] in the widget’s instance
11106 * initializer.
11107 */
11108void
11109gtk_widget_class_set_template_from_resource (GtkWidgetClass *widget_class,
11110 const char *resource_name)
11111{
11112 GError *error = NULL;
11113 GBytes *bytes = NULL;
11114
11115 g_return_if_fail (GTK_IS_WIDGET_CLASS (widget_class));
11116 g_return_if_fail (widget_class->priv->template == NULL);
11117 g_return_if_fail (resource_name && resource_name[0]);
11118
11119 /* This is a hack, because class initializers now access resources
11120 * and GIR/gtk-doc initializes classes without initializing GTK,
11121 * we ensure that our base resources are registered here and
11122 * avoid warnings which building GIRs/documentation.
11123 */
11124 _gtk_ensure_resources ();
11125
11126 bytes = g_resources_lookup_data (path: resource_name, lookup_flags: 0, error: &error);
11127 if (!bytes)
11128 {
11129 g_critical ("Unable to load resource for composite template for type '%s': %s",
11130 G_OBJECT_CLASS_NAME (widget_class), error->message);
11131 g_error_free (error);
11132 return;
11133 }
11134
11135 gtk_widget_class_set_template (widget_class, template_bytes: bytes);
11136 g_bytes_unref (bytes);
11137}
11138
11139/**
11140 * gtk_widget_class_bind_template_callback_full:
11141 * @widget_class: A `GtkWidgetClass`
11142 * @callback_name: The name of the callback as expected in the template XML
11143 * @callback_symbol: (scope async): The callback symbol
11144 *
11145 * Declares a @callback_symbol to handle @callback_name from
11146 * the template XML defined for @widget_type.
11147 *
11148 * This function is not supported after [method@Gtk.WidgetClass.set_template_scope]
11149 * has been used on @widget_class. See [method@Gtk.BuilderCScope.add_callback_symbol].
11150 *
11151 * Note that this must be called from a composite widget classes
11152 * class initializer after calling [method@Gtk.WidgetClass.set_template].
11153 */
11154void
11155gtk_widget_class_bind_template_callback_full (GtkWidgetClass *widget_class,
11156 const char *callback_name,
11157 GCallback callback_symbol)
11158{
11159 GtkWidgetTemplate *template;
11160
11161 g_return_if_fail (GTK_IS_WIDGET_CLASS (widget_class));
11162 g_return_if_fail (widget_class->priv->template != NULL);
11163 g_return_if_fail (callback_name && callback_name[0]);
11164 g_return_if_fail (callback_symbol != NULL);
11165
11166 template = widget_class->priv->template;
11167 if (template->scope == NULL)
11168 template->scope = gtk_builder_cscope_new ();
11169
11170 if (GTK_IS_BUILDER_CSCOPE (ptr: template->scope))
11171 {
11172 gtk_builder_cscope_add_callback_symbol (self: GTK_BUILDER_CSCOPE (ptr: template->scope),
11173 callback_name,
11174 callback_symbol);
11175 }
11176 else
11177 {
11178 g_critical ("Adding a callback to %s, but scope is not a GtkBuilderCScope.", G_OBJECT_CLASS_NAME (widget_class));
11179 }
11180}
11181
11182/**
11183 * gtk_widget_class_set_template_scope:
11184 * @widget_class: A `GtkWidgetClass`
11185 * @scope: (transfer none): The `GtkBuilderScope` to use when loading
11186 * the class template
11187 *
11188 * For use in language bindings, this will override the default
11189 * `GtkBuilderScope` to be used when parsing GtkBuilder XML from
11190 * this class’s template data.
11191 *
11192 * Note that this must be called from a composite widget classes class
11193 * initializer after calling [method@GtkWidgetClass.set_template].
11194 */
11195void
11196gtk_widget_class_set_template_scope (GtkWidgetClass *widget_class,
11197 GtkBuilderScope *scope)
11198{
11199 g_return_if_fail (GTK_IS_WIDGET_CLASS (widget_class));
11200 g_return_if_fail (widget_class->priv->template != NULL);
11201 g_return_if_fail (GTK_IS_BUILDER_SCOPE (scope));
11202
11203 /* Defensive, destroy any previously set data */
11204 g_set_object (&widget_class->priv->template->scope, scope);
11205}
11206
11207/**
11208 * gtk_widget_class_bind_template_child_full:
11209 * @widget_class: A `GtkWidgetClass`
11210 * @name: The “id” of the child defined in the template XML
11211 * @internal_child: Whether the child should be accessible as an “internal-child”
11212 * when this class is used in GtkBuilder XML
11213 * @struct_offset: The structure offset into the composite widget’s instance
11214 * public or private structure where the automated child pointer should be set,
11215 * or 0 to not assign the pointer.
11216 *
11217 * Automatically assign an object declared in the class template XML to
11218 * be set to a location on a freshly built instance’s private data, or
11219 * alternatively accessible via [method@Gtk.Widget.get_template_child].
11220 *
11221 * The struct can point either into the public instance, then you should
11222 * use `G_STRUCT_OFFSET(WidgetType, member)` for @struct_offset, or in the
11223 * private struct, then you should use `G_PRIVATE_OFFSET(WidgetType, member)`.
11224 *
11225 * An explicit strong reference will be held automatically for the duration
11226 * of your instance’s life cycle, it will be released automatically when
11227 * `GObjectClass.dispose()` runs on your instance and if a @struct_offset
11228 * that is `!= 0` is specified, then the automatic location in your instance
11229 * public or private data will be set to %NULL. You can however access an
11230 * automated child pointer the first time your classes `GObjectClass.dispose()`
11231 * runs, or alternatively in [signal@Gtk.Widget::destroy].
11232 *
11233 * If @internal_child is specified, [vfunc@Gtk.Buildable.get_internal_child]
11234 * will be automatically implemented by the `GtkWidget` class so there is no
11235 * need to implement it manually.
11236 *
11237 * The wrapper macros [func@Gtk.widget_class_bind_template_child],
11238 * [func@Gtk.widget_class_bind_template_child_internal],
11239 * [func@Gtk.widget_class_bind_template_child_private] and
11240 * [func@Gtk.widget_class_bind_template_child_internal_private]
11241 * might be more convenient to use.
11242 *
11243 * Note that this must be called from a composite widget classes class
11244 * initializer after calling [method@Gtk.WidgetClass.set_template].
11245 */
11246void
11247gtk_widget_class_bind_template_child_full (GtkWidgetClass *widget_class,
11248 const char *name,
11249 gboolean internal_child,
11250 gssize struct_offset)
11251{
11252 AutomaticChildClass *child_class;
11253
11254 g_return_if_fail (GTK_IS_WIDGET_CLASS (widget_class));
11255 g_return_if_fail (widget_class->priv->template != NULL);
11256 g_return_if_fail (name && name[0]);
11257
11258 child_class = template_child_class_new (name,
11259 internal_child,
11260 offset: struct_offset);
11261 widget_class->priv->template->children =
11262 g_slist_prepend (list: widget_class->priv->template->children, data: child_class);
11263}
11264
11265/**
11266 * gtk_widget_get_template_child:
11267 * @widget: A `GtkWidget`
11268 * @widget_type: The `GType` to get a template child for
11269 * @name: The “id” of the child defined in the template XML
11270 *
11271 * Fetch an object build from the template XML for @widget_type in
11272 * this @widget instance.
11273 *
11274 * This will only report children which were previously declared
11275 * with [method@Gtk.WidgetClass.bind_template_child_full] or one of its
11276 * variants.
11277 *
11278 * This function is only meant to be called for code which is private
11279 * to the @widget_type which declared the child and is meant for language
11280 * bindings which cannot easily make use of the GObject structure offsets.
11281 *
11282 * Returns: (transfer none): The object built in the template XML with
11283 * the id @name
11284 */
11285GObject *
11286gtk_widget_get_template_child (GtkWidget *widget,
11287 GType widget_type,
11288 const char *name)
11289{
11290 GHashTable *auto_child_hash;
11291 GObject *ret = NULL;
11292
11293 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
11294 g_return_val_if_fail (g_type_name (widget_type) != NULL, NULL);
11295 g_return_val_if_fail (name && name[0], NULL);
11296
11297 auto_child_hash = get_auto_child_hash (widget, type: widget_type, FALSE);
11298
11299 if (auto_child_hash)
11300 ret = g_hash_table_lookup (hash_table: auto_child_hash, key: name);
11301
11302 return ret;
11303}
11304
11305/**
11306 * gtk_widget_activate_action_variant: (rename-to gtk_widget_activate_action)
11307 * @widget: a `GtkWidget`
11308 * @name: the name of the action to activate
11309 * @args: (nullable): parameters to use
11310 *
11311 * Looks up the action in the action groups associated with
11312 * @widget and its ancestors, and activates it.
11313 *
11314 * If the action is in an action group added with
11315 * [method@Gtk.Widget.insert_action_group], the @name is expected
11316 * to be prefixed with the prefix that was used when the group was
11317 * inserted.
11318 *
11319 * The arguments must match the actions expected parameter type,
11320 * as returned by `g_action_get_parameter_type()`.
11321 *
11322 * Returns: %TRUE if the action was activated, %FALSE if the
11323 * action does not exist.
11324 */
11325gboolean
11326gtk_widget_activate_action_variant (GtkWidget *widget,
11327 const char *name,
11328 GVariant *args)
11329{
11330 GtkActionMuxer *muxer;
11331
11332 muxer = _gtk_widget_get_action_muxer (widget, FALSE);
11333 if (muxer == NULL)
11334 return FALSE;
11335
11336 if (!gtk_action_muxer_has_action (muxer, action_name: name))
11337 return FALSE;
11338
11339 gtk_action_muxer_activate_action (muxer, action_name: name, parameter: args);
11340
11341 return TRUE;
11342}
11343
11344/**
11345 * gtk_widget_activate_action:
11346 * @widget: a `GtkWidget`
11347 * @name: the name of the action to activate
11348 * @format_string: GVariant format string for arguments or %NULL
11349 * for no arguments
11350 * @...: arguments, as given by format string
11351 *
11352 * Looks up the action in the action groups associated
11353 * with @widget and its ancestors, and activates it.
11354 *
11355 * This is a wrapper around [method@Gtk.Widget.activate_action_variant]
11356 * that constructs the @args variant according to @format_string.
11357 *
11358 * Returns: %TRUE if the action was activated, %FALSE if the action
11359 * does not exist
11360 */
11361gboolean
11362gtk_widget_activate_action (GtkWidget *widget,
11363 const char *name,
11364 const char *format_string,
11365 ...)
11366{
11367 GVariant *parameters = NULL;
11368 gboolean result;
11369
11370 if (format_string != NULL)
11371 {
11372 va_list args;
11373
11374 va_start (args, format_string);
11375 parameters = g_variant_new_va (format_string, NULL, app: &args);
11376 va_end (args);
11377
11378 g_variant_ref_sink (value: parameters);
11379 }
11380
11381 result = gtk_widget_activate_action_variant (widget, name, args: parameters);
11382
11383 g_clear_pointer (&parameters, g_variant_unref);
11384
11385 return result;
11386}
11387
11388/**
11389 * gtk_widget_activate_default:
11390 * @widget: a `GtkWidget`
11391 *
11392 * Activates the `default.activate` action from @widget.
11393 */
11394void
11395gtk_widget_activate_default (GtkWidget *widget)
11396{
11397 gtk_widget_activate_action (widget, name: "default.activate", NULL);
11398}
11399
11400void
11401gtk_widget_cancel_event_sequence (GtkWidget *widget,
11402 GtkGesture *gesture,
11403 GdkEventSequence *sequence,
11404 GtkEventSequenceState state)
11405{
11406 gboolean handled = FALSE;
11407 GtkWidget *event_widget;
11408 gboolean cancel = TRUE;
11409 GdkEvent *event;
11410
11411 handled = _gtk_widget_set_sequence_state_internal (widget, sequence,
11412 state, emitter: gesture);
11413
11414 if (!handled || state != GTK_EVENT_SEQUENCE_CLAIMED)
11415 return;
11416
11417 event = _gtk_widget_get_last_event (widget, sequence, target: &event_widget);
11418
11419 if (!event)
11420 return;
11421
11422 while (event_widget)
11423 {
11424 if (event_widget == widget)
11425 cancel = FALSE;
11426 else if (cancel)
11427 _gtk_widget_cancel_sequence (widget: event_widget, sequence);
11428 else
11429 _gtk_widget_set_sequence_state_internal (widget: event_widget, sequence,
11430 state: GTK_EVENT_SEQUENCE_DENIED,
11431 NULL);
11432
11433 event_widget = _gtk_widget_get_parent (widget: event_widget);
11434 }
11435
11436}
11437
11438/**
11439 * gtk_widget_add_controller:
11440 * @widget: a `GtkWidget`
11441 * @controller: (transfer full): a `GtkEventController` that hasn't been
11442 * added to a widget yet
11443 *
11444 * Adds @controller to @widget so that it will receive events.
11445 *
11446 * You will usually want to call this function right after
11447 * creating any kind of [class@Gtk.EventController].
11448 */
11449void
11450gtk_widget_add_controller (GtkWidget *widget,
11451 GtkEventController *controller)
11452{
11453 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
11454
11455 g_return_if_fail (GTK_IS_WIDGET (widget));
11456 g_return_if_fail (GTK_IS_EVENT_CONTROLLER (controller));
11457 g_return_if_fail (gtk_event_controller_get_widget (controller) == NULL);
11458
11459 GTK_EVENT_CONTROLLER_GET_CLASS (controller)->set_widget (controller, widget);
11460
11461 priv->event_controllers = g_list_prepend (list: priv->event_controllers, data: controller);
11462
11463 if (priv->controller_observer)
11464 gtk_list_list_model_item_added_at (self: priv->controller_observer, position: 0);
11465}
11466
11467/**
11468 * gtk_widget_remove_controller:
11469 * @widget: a `GtkWidget`
11470 * @controller: (transfer none): a `GtkEventController`
11471 *
11472 * Removes @controller from @widget, so that it doesn't process
11473 * events anymore.
11474 *
11475 * It should not be used again.
11476 *
11477 * Widgets will remove all event controllers automatically when they
11478 * are destroyed, there is normally no need to call this function.
11479 */
11480void
11481gtk_widget_remove_controller (GtkWidget *widget,
11482 GtkEventController *controller)
11483{
11484 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
11485 GList *before, *list;
11486
11487 g_return_if_fail (GTK_IS_WIDGET (widget));
11488 g_return_if_fail (GTK_IS_EVENT_CONTROLLER (controller));
11489 g_return_if_fail (gtk_event_controller_get_widget (controller) == widget);
11490
11491 GTK_EVENT_CONTROLLER_GET_CLASS (controller)->unset_widget (controller);
11492
11493 list = g_list_find (list: priv->event_controllers, data: controller);
11494 before = list->prev;
11495 priv->event_controllers = g_list_delete_link (list: priv->event_controllers, link_: list);
11496 g_object_unref (object: controller);
11497
11498 if (priv->controller_observer)
11499 gtk_list_list_model_item_removed (self: priv->controller_observer, previous: before);
11500}
11501
11502void
11503gtk_widget_reset_controllers (GtkWidget *widget)
11504{
11505 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
11506 GList *l;
11507
11508 /* Reset all controllers */
11509 for (l = priv->event_controllers; l; l = l->next)
11510 {
11511 GtkEventController *controller = l->data;
11512
11513 if (controller == NULL)
11514 continue;
11515
11516 gtk_event_controller_reset (controller);
11517 }
11518}
11519
11520GtkEventController **
11521gtk_widget_list_controllers (GtkWidget *widget,
11522 GtkPropagationPhase phase,
11523 guint *out_n_controllers)
11524{
11525 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
11526 GPtrArray *controllers = g_ptr_array_new ();
11527 GList *l;
11528
11529 g_assert (out_n_controllers);
11530
11531 for (l = priv->event_controllers; l; l = l->next)
11532 {
11533 GtkEventController *controller = l->data;
11534
11535 if (gtk_event_controller_get_propagation_phase (controller) == phase)
11536 g_ptr_array_add (array: controllers, data: controller);
11537 }
11538
11539 *out_n_controllers = controllers->len;
11540
11541 return (GtkEventController **)g_ptr_array_free (array: controllers, FALSE);
11542}
11543
11544static GskRenderNode *
11545gtk_widget_create_render_node (GtkWidget *widget,
11546 GtkSnapshot *snapshot)
11547{
11548 GtkWidgetClass *klass = GTK_WIDGET_GET_CLASS (widget);
11549 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
11550 GtkCssBoxes boxes;
11551 GtkCssValue *filter_value;
11552 double css_opacity, opacity;
11553 GtkCssStyle *style;
11554
11555 style = gtk_css_node_get_style (cssnode: priv->cssnode);
11556
11557 css_opacity = _gtk_css_number_value_get (number: style->other->opacity, one_hundred_percent: 100);
11558 opacity = CLAMP (css_opacity, 0.0, 1.0) * priv->user_alpha / 255.0;
11559
11560 if (opacity <= 0.0)
11561 return NULL;
11562
11563 gtk_css_boxes_init (boxes: &boxes, widget);
11564
11565 gtk_snapshot_push_collect (snapshot);
11566 gtk_snapshot_push_debug (snapshot,
11567 message: "RenderNode for %s %p",
11568 G_OBJECT_TYPE_NAME (widget), widget);
11569
11570 filter_value = style->other->filter;
11571 gtk_css_filter_value_push_snapshot (filter: filter_value, snapshot);
11572
11573 if (opacity < 1.0)
11574 gtk_snapshot_push_opacity (snapshot, opacity);
11575
11576 gtk_css_style_snapshot_background (boxes: &boxes, snapshot);
11577 gtk_css_style_snapshot_border (boxes: &boxes, snapshot);
11578
11579 if (priv->overflow == GTK_OVERFLOW_HIDDEN)
11580 {
11581 gtk_snapshot_push_rounded_clip (snapshot, bounds: gtk_css_boxes_get_padding_box (boxes: &boxes));
11582 klass->snapshot (widget, snapshot);
11583 gtk_snapshot_pop (snapshot);
11584 }
11585 else
11586 {
11587 klass->snapshot (widget, snapshot);
11588 }
11589
11590 gtk_css_style_snapshot_outline (boxes: &boxes, snapshot);
11591
11592 if (opacity < 1.0)
11593 gtk_snapshot_pop (snapshot);
11594
11595 gtk_css_filter_value_pop_snapshot (filter: filter_value, snapshot);
11596
11597 gtk_snapshot_pop (snapshot);
11598
11599 return gtk_snapshot_pop_collect (snapshot);
11600}
11601
11602static void
11603gtk_widget_do_snapshot (GtkWidget *widget,
11604 GtkSnapshot *snapshot)
11605{
11606 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
11607 GskRenderNode *render_node;
11608
11609 if (!priv->draw_needed)
11610 return;
11611
11612 g_assert (priv->mapped);
11613
11614 if (_gtk_widget_get_alloc_needed (widget))
11615 {
11616 g_warning ("Trying to snapshot %s %p without a current allocation", gtk_widget_get_name (widget), widget);
11617 return;
11618 }
11619
11620 gtk_widget_push_paintables (widget);
11621
11622 render_node = gtk_widget_create_render_node (widget, snapshot);
11623 /* This can happen when nested drawing happens and a widget contains itself
11624 * or when we replace a clipped area
11625 */
11626 g_clear_pointer (&priv->render_node, gsk_render_node_unref);
11627 priv->render_node = render_node;
11628
11629 priv->draw_needed = FALSE;
11630
11631 gtk_widget_pop_paintables (widget);
11632 gtk_widget_update_paintables (widget);
11633}
11634
11635void
11636gtk_widget_snapshot (GtkWidget *widget,
11637 GtkSnapshot *snapshot)
11638{
11639 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
11640
11641 if (!_gtk_widget_get_mapped (widget))
11642 return;
11643
11644 gtk_widget_do_snapshot (widget, snapshot);
11645
11646 if (priv->render_node)
11647 gtk_snapshot_append_node (snapshot, node: priv->render_node);
11648}
11649
11650void
11651gtk_widget_render (GtkWidget *widget,
11652 GdkSurface *surface,
11653 const cairo_region_t *region)
11654{
11655 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
11656 GtkSnapshot *snapshot;
11657 GskRenderer *renderer;
11658 GskRenderNode *root;
11659 double x, y;
11660 gint64 before_snapshot G_GNUC_UNUSED;
11661 gint64 before_render G_GNUC_UNUSED;
11662
11663 before_snapshot = GDK_PROFILER_CURRENT_TIME;
11664 before_render = 0;
11665
11666 if (!GTK_IS_NATIVE (ptr: widget))
11667 return;
11668
11669 renderer = gtk_native_get_renderer (self: GTK_NATIVE (ptr: widget));
11670 if (renderer == NULL)
11671 return;
11672
11673 snapshot = gtk_snapshot_new ();
11674 gtk_native_get_surface_transform (self: GTK_NATIVE (ptr: widget), x: &x, y: &y);
11675 gtk_snapshot_translate (snapshot, point: &GRAPHENE_POINT_INIT (x, y));
11676 gtk_widget_snapshot (widget, snapshot);
11677 root = gtk_snapshot_free_to_node (snapshot);
11678
11679 if (GDK_PROFILER_IS_RUNNING)
11680 {
11681 before_render = GDK_PROFILER_CURRENT_TIME;
11682 gdk_profiler_add_mark (before_snapshot, (before_render - before_snapshot), "widget snapshot", "");
11683 }
11684
11685 if (root != NULL)
11686 {
11687 root = gtk_inspector_prepare_render (widget,
11688 renderer,
11689 surface,
11690 region,
11691 root,
11692 widget_node: priv->render_node);
11693
11694 gsk_renderer_render (renderer, root, region);
11695
11696 gsk_render_node_unref (node: root);
11697
11698 gdk_profiler_end_mark (before_render, "widget render", "");
11699 }
11700}
11701
11702static void
11703gtk_widget_child_observer_destroyed (gpointer widget)
11704{
11705 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
11706
11707 priv->children_observer = NULL;
11708}
11709
11710/**
11711 * gtk_widget_observe_children:
11712 * @widget: a `GtkWidget`
11713 *
11714 * Returns a `GListModel` to track the children of @widget.
11715 *
11716 * Calling this function will enable extra internal bookkeeping
11717 * to track children and emit signals on the returned listmodel.
11718 * It may slow down operations a lot.
11719 *
11720 * Applications should try hard to avoid calling this function
11721 * because of the slowdowns.
11722 *
11723 * Returns: (transfer full) (attributes element-type=GtkWidget):
11724 * a `GListModel` tracking @widget's children
11725 */
11726GListModel *
11727gtk_widget_observe_children (GtkWidget *widget)
11728{
11729 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
11730
11731 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
11732
11733 if (priv->children_observer)
11734 return g_object_ref (G_LIST_MODEL (priv->children_observer));
11735
11736 priv->children_observer = gtk_list_list_model_new (get_first: (gpointer) gtk_widget_get_first_child,
11737 get_next: (gpointer) gtk_widget_get_next_sibling,
11738 get_previous: (gpointer) gtk_widget_get_prev_sibling,
11739 get_last: (gpointer) gtk_widget_get_last_child,
11740 get_item: (gpointer) g_object_ref,
11741 data: widget,
11742 notify: gtk_widget_child_observer_destroyed);
11743
11744 return G_LIST_MODEL (ptr: priv->children_observer);
11745}
11746
11747static void
11748gtk_widget_controller_observer_destroyed (gpointer widget)
11749{
11750 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
11751
11752 priv->controller_observer = NULL;
11753}
11754
11755static gpointer
11756gtk_widget_controller_list_get_first (gpointer widget)
11757{
11758 return GTK_WIDGET (widget)->priv->event_controllers;
11759}
11760
11761static gpointer
11762gtk_widget_controller_list_get_next (gpointer item,
11763 gpointer widget)
11764{
11765 return g_list_next (item);
11766}
11767
11768static gpointer
11769gtk_widget_controller_list_get_prev (gpointer item,
11770 gpointer widget)
11771{
11772 return g_list_previous (item);
11773}
11774
11775static gpointer
11776gtk_widget_controller_list_get_item (gpointer item,
11777 gpointer widget)
11778{
11779 return g_object_ref (((GList *) item)->data);
11780}
11781
11782/**
11783 * gtk_widget_observe_controllers:
11784 * @widget: a `GtkWidget`
11785 *
11786 * Returns a `GListModel` to track the [class@Gtk.EventController]s
11787 * of @widget.
11788 *
11789 * Calling this function will enable extra internal bookkeeping
11790 * to track controllers and emit signals on the returned listmodel.
11791 * It may slow down operations a lot.
11792 *
11793 * Applications should try hard to avoid calling this function
11794 * because of the slowdowns.
11795 *
11796 * Returns: (transfer full) (attributes element-type=GtkEventController):
11797 * a `GListModel` tracking @widget's controllers
11798 */
11799GListModel *
11800gtk_widget_observe_controllers (GtkWidget *widget)
11801{
11802 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
11803
11804 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
11805
11806 if (priv->controller_observer)
11807 return g_object_ref (G_LIST_MODEL (priv->controller_observer));
11808
11809 priv->controller_observer = gtk_list_list_model_new (get_first: gtk_widget_controller_list_get_first,
11810 get_next: gtk_widget_controller_list_get_next,
11811 get_previous: gtk_widget_controller_list_get_prev,
11812 NULL,
11813 get_item: gtk_widget_controller_list_get_item,
11814 data: widget,
11815 notify: gtk_widget_controller_observer_destroyed);
11816
11817 return G_LIST_MODEL (ptr: priv->controller_observer);
11818}
11819
11820/**
11821 * gtk_widget_get_first_child:
11822 * @widget: a `GtkWidget`
11823 *
11824 * Returns the widgets first child.
11825 *
11826 * This API is primarily meant for widget implementations.
11827 *
11828 * Returns: (transfer none) (nullable): The widget's first child
11829 */
11830GtkWidget *
11831gtk_widget_get_first_child (GtkWidget *widget)
11832{
11833 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
11834
11835 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
11836
11837 return priv->first_child;
11838}
11839
11840/**
11841 * gtk_widget_get_last_child:
11842 * @widget: a `GtkWidget`
11843 *
11844 * Returns the widgets last child.
11845 *
11846 * This API is primarily meant for widget implementations.
11847 *
11848 * Returns: (transfer none) (nullable): The widget's last child
11849 */
11850GtkWidget *
11851gtk_widget_get_last_child (GtkWidget *widget)
11852{
11853 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
11854
11855 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
11856
11857 return priv->last_child;
11858}
11859
11860/**
11861 * gtk_widget_get_next_sibling:
11862 * @widget: a `GtkWidget`
11863 *
11864 * Returns the widgets next sibling.
11865 *
11866 * This API is primarily meant for widget implementations.
11867 *
11868 * Returns: (transfer none) (nullable): The widget's next sibling
11869 */
11870GtkWidget *
11871gtk_widget_get_next_sibling (GtkWidget *widget)
11872{
11873 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
11874
11875 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
11876
11877 return priv->next_sibling;
11878}
11879
11880/**
11881 * gtk_widget_get_prev_sibling:
11882 * @widget: a `GtkWidget`
11883 *
11884 * Returns the widgets previous sibling.
11885 *
11886 * This API is primarily meant for widget implementations.
11887 *
11888 * Returns: (transfer none) (nullable): The widget's previous sibling
11889 */
11890GtkWidget *
11891gtk_widget_get_prev_sibling (GtkWidget *widget)
11892{
11893 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
11894
11895 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
11896
11897 return priv->prev_sibling;
11898}
11899
11900/**
11901 * gtk_widget_insert_after:
11902 * @widget: a `GtkWidget`
11903 * @parent: the parent `GtkWidget` to insert @widget into
11904 * @previous_sibling: (nullable): the new previous sibling of @widget
11905 *
11906 * Inserts @widget into the child widget list of @parent.
11907 *
11908 * It will be placed after @previous_sibling, or at the beginning if
11909 * @previous_sibling is %NULL.
11910 *
11911 * After calling this function, `gtk_widget_get_prev_sibling(widget)`
11912 * will return @previous_sibling.
11913 *
11914 * If @parent is already set as the parent widget of @widget, this
11915 * function can also be used to reorder @widget in the child widget
11916 * list of @parent.
11917 *
11918 * This API is primarily meant for widget implementations; if you are
11919 * just using a widget, you *must* use its own API for adding children.
11920 */
11921void
11922gtk_widget_insert_after (GtkWidget *widget,
11923 GtkWidget *parent,
11924 GtkWidget *previous_sibling)
11925{
11926 g_return_if_fail (GTK_IS_WIDGET (widget));
11927 g_return_if_fail (GTK_IS_WIDGET (parent));
11928 g_return_if_fail (previous_sibling == NULL || GTK_IS_WIDGET (previous_sibling));
11929 g_return_if_fail (previous_sibling == NULL || _gtk_widget_get_parent (previous_sibling) == parent);
11930
11931 if (widget == previous_sibling ||
11932 (previous_sibling && _gtk_widget_get_prev_sibling (widget) == previous_sibling))
11933 return;
11934
11935 if (!previous_sibling && _gtk_widget_get_first_child (widget: parent) == widget)
11936 return;
11937
11938 gtk_widget_reposition_after (widget,
11939 parent,
11940 previous_sibling);
11941}
11942
11943/**
11944 * gtk_widget_insert_before:
11945 * @widget: a `GtkWidget`
11946 * @parent: the parent `GtkWidget` to insert @widget into
11947 * @next_sibling: (nullable): the new next sibling of @widget
11948 *
11949 * Inserts @widget into the child widget list of @parent.
11950 *
11951 * It will be placed before @next_sibling, or at the end if
11952 * @next_sibling is %NULL.
11953 *
11954 * After calling this function, `gtk_widget_get_next_sibling(widget)`
11955 * will return @next_sibling.
11956 *
11957 * If @parent is already set as the parent widget of @widget, this function
11958 * can also be used to reorder @widget in the child widget list of @parent.
11959 *
11960 * This API is primarily meant for widget implementations; if you are
11961 * just using a widget, you *must* use its own API for adding children.
11962 */
11963void
11964gtk_widget_insert_before (GtkWidget *widget,
11965 GtkWidget *parent,
11966 GtkWidget *next_sibling)
11967{
11968 g_return_if_fail (GTK_IS_WIDGET (widget));
11969 g_return_if_fail (GTK_IS_WIDGET (parent));
11970 g_return_if_fail (next_sibling == NULL || GTK_IS_WIDGET (next_sibling));
11971 g_return_if_fail (next_sibling == NULL || _gtk_widget_get_parent (next_sibling) == parent);
11972
11973 if (widget == next_sibling ||
11974 (next_sibling && _gtk_widget_get_next_sibling (widget) == next_sibling))
11975 return;
11976
11977 if (!next_sibling && _gtk_widget_get_last_child (widget: parent) == widget)
11978 return;
11979
11980 gtk_widget_reposition_after (widget, parent,
11981 previous_sibling: next_sibling ? _gtk_widget_get_prev_sibling (widget: next_sibling) :
11982 _gtk_widget_get_last_child (widget: parent));
11983}
11984
11985void
11986gtk_widget_forall (GtkWidget *widget,
11987 GtkCallback callback,
11988 gpointer user_data)
11989{
11990 GtkWidget *child;
11991 g_return_if_fail (GTK_IS_WIDGET (widget));
11992
11993 child = _gtk_widget_get_first_child (widget);
11994 while (child)
11995 {
11996 GtkWidget *next = _gtk_widget_get_next_sibling (widget: child);
11997
11998 callback(child, user_data);
11999
12000 child = next;
12001 }
12002}
12003
12004/**
12005 * gtk_widget_snapshot_child:
12006 * @widget: a `GtkWidget`
12007 * @child: a child of @widget
12008 * @snapshot: `GtkSnapshot` as passed to the widget. In particular, no
12009 * calls to gtk_snapshot_translate() or other transform calls should
12010 * have been made.
12011 *
12012 * Snapshot the a child of @widget.
12013 *
12014 * When a widget receives a call to the snapshot function,
12015 * it must send synthetic [vfunc@Gtk.Widget.snapshot] calls
12016 * to all children. This function provides a convenient way
12017 * of doing this. A widget, when it receives a call to its
12018 * [vfunc@Gtk.Widget.snapshot] function, calls
12019 * gtk_widget_snapshot_child() once for each child, passing in
12020 * the @snapshot the widget received.
12021 *
12022 * gtk_widget_snapshot_child() takes care of translating the origin of
12023 * @snapshot, and deciding whether the child needs to be snapshot.
12024 *
12025 * This function does nothing for children that implement `GtkNative`.
12026 */
12027void
12028gtk_widget_snapshot_child (GtkWidget *widget,
12029 GtkWidget *child,
12030 GtkSnapshot *snapshot)
12031{
12032 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: child);
12033
12034 g_return_if_fail (_gtk_widget_get_parent (child) == widget);
12035 g_return_if_fail (snapshot != NULL);
12036
12037 if (!_gtk_widget_get_mapped (widget: child))
12038 return;
12039
12040 if (GTK_IS_NATIVE (ptr: child))
12041 return;
12042
12043 gtk_widget_do_snapshot (widget: child, snapshot);
12044
12045 if (!priv->render_node)
12046 return;
12047
12048 if (priv->transform)
12049 {
12050 GskRenderNode *transform_node = gsk_transform_node_new (child: priv->render_node,
12051 transform: priv->transform);
12052
12053 gtk_snapshot_append_node (snapshot, node: transform_node);
12054 gsk_render_node_unref (node: transform_node);
12055 }
12056 else
12057 {
12058 gtk_snapshot_append_node (snapshot, node: priv->render_node);
12059 }
12060}
12061
12062/**
12063 * gtk_widget_set_focus_child:
12064 * @widget: a `GtkWidget`
12065 * @child: (nullable): a direct child widget of @widget or %NULL
12066 * to unset the focus child of @widget
12067 *
12068 * Set @child as the current focus child of @widget.
12069 *
12070 * This function is only suitable for widget implementations.
12071 * If you want a certain widget to get the input focus, call
12072 * [method@Gtk.Widget.grab_focus] on it.
12073 */
12074void
12075gtk_widget_set_focus_child (GtkWidget *widget,
12076 GtkWidget *child)
12077{
12078 g_return_if_fail (GTK_IS_WIDGET (widget));
12079
12080 if (child != NULL)
12081 {
12082 g_return_if_fail (GTK_IS_WIDGET (child));
12083 g_return_if_fail (gtk_widget_get_parent (child) == widget);
12084 }
12085
12086 GTK_WIDGET_GET_CLASS (widget)->set_focus_child (widget, child);
12087}
12088
12089static void
12090gtk_widget_real_set_focus_child (GtkWidget *widget,
12091 GtkWidget *child)
12092{
12093 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
12094
12095 g_set_object (&priv->focus_child, child);
12096}
12097
12098/**
12099 * gtk_widget_get_focus_child:
12100 * @widget: a `GtkWidget`
12101 *
12102 * Returns the current focus child of @widget.
12103 *
12104 * Returns: (nullable) (transfer none): The current focus
12105 * child of @widget
12106 */
12107GtkWidget *
12108gtk_widget_get_focus_child (GtkWidget *widget)
12109{
12110 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
12111
12112 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
12113
12114 return priv->focus_child;
12115}
12116
12117/**
12118 * gtk_widget_set_cursor: (attributes org.gtk.Method.set_property=cursor)
12119 * @widget: a `GtkWidget`
12120 * @cursor: (nullable): the new cursor
12121 *
12122 * Sets the cursor to be shown when pointer devices point
12123 * towards @widget.
12124 *
12125 * If the @cursor is NULL, @widget will use the cursor
12126 * inherited from the parent widget.
12127 */
12128void
12129gtk_widget_set_cursor (GtkWidget *widget,
12130 GdkCursor *cursor)
12131{
12132 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
12133 GtkRoot *root;
12134
12135 g_return_if_fail (GTK_IS_WIDGET (widget));
12136 g_return_if_fail (cursor == NULL || GDK_IS_CURSOR (cursor));
12137
12138 if (!g_set_object (&priv->cursor, cursor))
12139 return;
12140
12141 root = _gtk_widget_get_root (widget);
12142 if (GTK_IS_WINDOW (root))
12143 gtk_window_maybe_update_cursor (GTK_WINDOW (root), widget, NULL);
12144
12145 g_object_notify_by_pspec (G_OBJECT (widget), pspec: widget_props[PROP_CURSOR]);
12146}
12147
12148/**
12149 * gtk_widget_set_cursor_from_name:
12150 * @widget: a `GtkWidget`
12151 * @name: (nullable): The name of the cursor
12152 *
12153 * Sets a named cursor to be shown when pointer devices point
12154 * towards @widget.
12155 *
12156 * This is a utility function that creates a cursor via
12157 * [ctor@Gdk.Cursor.new_from_name] and then sets it on @widget
12158 * with [method@Gtk.Widget.set_cursor]. See those functions for
12159 * details.
12160 *
12161 * On top of that, this function allows @name to be %NULL, which
12162 * will do the same as calling [method@Gtk.Widget.set_cursor]
12163 * with a %NULL cursor.
12164 */
12165void
12166gtk_widget_set_cursor_from_name (GtkWidget *widget,
12167 const char *name)
12168{
12169 g_return_if_fail (GTK_IS_WIDGET (widget));
12170
12171 if (name)
12172 {
12173 GdkCursor *cursor;
12174
12175 cursor = gdk_cursor_new_from_name (name, NULL);
12176 gtk_widget_set_cursor (widget, cursor);
12177 g_object_unref (object: cursor);
12178 }
12179 else
12180 {
12181 gtk_widget_set_cursor (widget, NULL);
12182 }
12183}
12184
12185/**
12186 * gtk_widget_get_cursor: (attributes org.gtk.Method.get_property=cursor)
12187 * @widget: a `GtkWidget`
12188 *
12189 * Queries the cursor set on @widget.
12190 *
12191 * See [method@Gtk.Widget.set_cursor] for details.
12192 *
12193 * Returns: (nullable) (transfer none): the cursor
12194 * currently in use or %NULL if the cursor is inherited
12195 */
12196GdkCursor *
12197gtk_widget_get_cursor (GtkWidget *widget)
12198{
12199 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
12200
12201 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
12202
12203 return priv->cursor;
12204}
12205
12206/**
12207 * gtk_widget_set_can_target: (attributes org.gtk.Method.set_property=can-target)
12208 * @widget: a `GtkWidget`
12209 * @can_target: whether this widget should be able to
12210 * receive pointer events
12211 *
12212 * Sets whether @widget can be the target of pointer events.
12213 */
12214void
12215gtk_widget_set_can_target (GtkWidget *widget,
12216 gboolean can_target)
12217{
12218 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
12219
12220 can_target = !!can_target;
12221
12222 if (priv->can_target == can_target)
12223 return;
12224
12225 priv->can_target = can_target;
12226
12227 g_object_notify_by_pspec (G_OBJECT (widget), pspec: widget_props[PROP_CAN_TARGET]);
12228}
12229
12230/**
12231 * gtk_widget_get_can_target: (attributes org.gtk.Method.get_property=can-target)
12232 * @widget: a `GtkWidget`
12233 *
12234 * Queries whether @widget can be the target of pointer events.
12235 *
12236 * Returns: %TRUE if @widget can receive pointer events
12237 */
12238gboolean
12239gtk_widget_get_can_target (GtkWidget *widget)
12240{
12241 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
12242
12243 return priv->can_target;
12244}
12245
12246/**
12247 * gtk_widget_get_width:
12248 * @widget: a `GtkWidget`
12249 *
12250 * Returns the content width of the widget.
12251 *
12252 * This function returns the width passed to its
12253 * size-allocate implementation, which is the width you
12254 * should be using in [vfunc@Gtk.Widget.snapshot].
12255 *
12256 * For pointer events, see [method@Gtk.Widget.contains].
12257 *
12258 * Returns: The width of @widget
12259 */
12260int
12261gtk_widget_get_width (GtkWidget *widget)
12262{
12263 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
12264
12265 g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
12266
12267 return priv->width;
12268}
12269
12270/**
12271 * gtk_widget_get_height:
12272 * @widget: a `GtkWidget`
12273 *
12274 * Returns the content height of the widget.
12275 *
12276 * This function returns the height passed to its
12277 * size-allocate implementation, which is the height you
12278 * should be using in [vfunc@Gtk.Widget.snapshot].
12279 *
12280 * For pointer events, see [method@Gtk.Widget.contains].
12281 *
12282 * Returns: The height of @widget
12283 */
12284int
12285gtk_widget_get_height (GtkWidget *widget)
12286{
12287 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
12288
12289 g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
12290
12291 return priv->height;
12292}
12293
12294/**
12295 * gtk_widget_get_size:
12296 * @widget: a `GtkWidget`
12297 * @orientation: the orientation to query
12298 *
12299 * Returns the content width or height of the widget.
12300 *
12301 * Which dimension is returned depends on @orientation.
12302 *
12303 * This is equivalent to calling [method@Gtk.Widget.get_width]
12304 * for %GTK_ORIENTATION_HORIZONTAL or [method@Gtk.Widget.get_height]
12305 * for %GTK_ORIENTATION_VERTICAL, but can be used when
12306 * writing orientation-independent code, such as when
12307 * implementing [iface@Gtk.Orientable] widgets.
12308 *
12309 * Returns: The size of @widget in @orientation.
12310 */
12311int
12312gtk_widget_get_size (GtkWidget *widget,
12313 GtkOrientation orientation)
12314{
12315 g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
12316
12317 if (orientation == GTK_ORIENTATION_HORIZONTAL)
12318 return gtk_widget_get_width (widget);
12319 else
12320 return gtk_widget_get_height (widget);
12321}
12322
12323/**
12324 * gtk_widget_class_set_layout_manager_type:
12325 * @widget_class: a `GtkWidgetClass`
12326 * @type: The object type that implements the `GtkLayoutManager`
12327 * for @widget_class
12328 *
12329 * Sets the type to be used for creating layout managers for
12330 * widgets of @widget_class.
12331 *
12332 * The given @type must be a subtype of [class@Gtk.LayoutManager].
12333 *
12334 * This function should only be called from class init functions
12335 * of widgets.
12336 */
12337void
12338gtk_widget_class_set_layout_manager_type (GtkWidgetClass *widget_class,
12339 GType type)
12340{
12341 GtkWidgetClassPrivate *priv;
12342
12343 g_return_if_fail (GTK_IS_WIDGET_CLASS (widget_class));
12344 g_return_if_fail (g_type_is_a (type, GTK_TYPE_LAYOUT_MANAGER));
12345
12346 priv = widget_class->priv;
12347
12348 priv->layout_manager_type = type;
12349}
12350
12351/**
12352 * gtk_widget_class_get_layout_manager_type:
12353 * @widget_class: a `GtkWidgetClass`
12354 *
12355 * Retrieves the type of the [class@Gtk.LayoutManager]
12356 * used by widgets of class @widget_class.
12357 *
12358 * See also: [method@Gtk.WidgetClass.set_layout_manager_type].
12359 *
12360 * Returns: type of a `GtkLayoutManager` subclass, or %G_TYPE_INVALID
12361 */
12362GType
12363gtk_widget_class_get_layout_manager_type (GtkWidgetClass *widget_class)
12364{
12365 GtkWidgetClassPrivate *priv;
12366
12367 g_return_val_if_fail (GTK_IS_WIDGET_CLASS (widget_class), G_TYPE_INVALID);
12368
12369 priv = widget_class->priv;
12370
12371 return priv->layout_manager_type;
12372}
12373
12374/**
12375 * gtk_widget_set_layout_manager: (attributes org.gtk.Method.set_property=layout-manager)
12376 * @widget: a `GtkWidget`
12377 * @layout_manager: (nullable) (transfer full): a `GtkLayoutManager`
12378 *
12379 * Sets the layout manager delegate instance that provides an
12380 * implementation for measuring and allocating the children of @widget.
12381 */
12382void
12383gtk_widget_set_layout_manager (GtkWidget *widget,
12384 GtkLayoutManager *layout_manager)
12385{
12386 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
12387
12388 g_return_if_fail (GTK_IS_WIDGET (widget));
12389 g_return_if_fail (layout_manager == NULL || GTK_IS_LAYOUT_MANAGER (layout_manager));
12390 g_return_if_fail (layout_manager == NULL || gtk_layout_manager_get_widget (layout_manager) == NULL);
12391
12392 if (priv->layout_manager == layout_manager)
12393 return;
12394
12395 if (priv->layout_manager)
12396 {
12397 gtk_layout_manager_set_widget (manager: priv->layout_manager, NULL);
12398 g_object_unref (object: priv->layout_manager);
12399 }
12400
12401 priv->layout_manager = layout_manager;
12402 if (priv->layout_manager != NULL)
12403 gtk_layout_manager_set_widget (manager: priv->layout_manager, widget);
12404
12405 gtk_widget_queue_resize (widget);
12406
12407 g_object_notify_by_pspec (G_OBJECT (widget), pspec: widget_props[PROP_LAYOUT_MANAGER]);
12408}
12409
12410/**
12411 * gtk_widget_get_layout_manager: (attributes org.gtk.Method.get_property=layout-manager)
12412 * @widget: a `GtkWidget`
12413 *
12414 * Retrieves the layout manager used by @widget.
12415 *
12416 * See [method@Gtk.Widget.set_layout_manager].
12417 *
12418 * Returns: (transfer none) (nullable): a `GtkLayoutManager`
12419 */
12420GtkLayoutManager *
12421gtk_widget_get_layout_manager (GtkWidget *widget)
12422{
12423 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
12424
12425 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
12426
12427 return priv->layout_manager;
12428}
12429
12430/**
12431 * gtk_widget_should_layout:
12432 * @widget: a widget
12433 *
12434 * Returns whether @widget should contribute to
12435 * the measuring and allocation of its parent.
12436 *
12437 * This is %FALSE for invisible children, but also
12438 * for children that have their own surface.
12439 *
12440 * Returns: %TRUE if child should be included in
12441 * measuring and allocating
12442 */
12443gboolean
12444gtk_widget_should_layout (GtkWidget *widget)
12445{
12446 if (!_gtk_widget_get_visible (widget))
12447 return FALSE;
12448
12449 if (GTK_IS_NATIVE (ptr: widget))
12450 return FALSE;
12451
12452 return TRUE;
12453}
12454
12455static void
12456gtk_widget_class_add_action (GtkWidgetClass *widget_class,
12457 GtkWidgetAction *action)
12458{
12459 GtkWidgetClassPrivate *priv = widget_class->priv;
12460
12461 GTK_NOTE(ACTIONS, g_message ("%sClass: Adding %s action\n",
12462 g_type_name (G_TYPE_FROM_CLASS (widget_class)),
12463 action->name));
12464
12465 action->next = priv->actions;
12466 priv->actions = action;
12467}
12468
12469/**
12470 * gtk_widget_class_install_action:
12471 * @widget_class: a `GtkWidgetClass`
12472 * @action_name: a prefixed action name, such as "clipboard.paste"
12473 * @parameter_type: (nullable): the parameter type
12474 * @activate: (scope notified): callback to use when the action is activated
12475 *
12476 * This should be called at class initialization time to specify
12477 * actions to be added for all instances of this class.
12478 *
12479 * Actions installed by this function are stateless. The only state
12480 * they have is whether they are enabled or not.
12481 */
12482void
12483gtk_widget_class_install_action (GtkWidgetClass *widget_class,
12484 const char *action_name,
12485 const char *parameter_type,
12486 GtkWidgetActionActivateFunc activate)
12487{
12488 GtkWidgetAction *action;
12489
12490 action = g_new0 (GtkWidgetAction, 1);
12491 action->owner = G_TYPE_FROM_CLASS (widget_class);
12492 action->name = g_strdup (str: action_name);
12493 if (parameter_type)
12494 action->parameter_type = g_variant_type_new (type_string: parameter_type);
12495 else
12496 action->parameter_type = NULL;
12497 action->activate = activate;
12498
12499 gtk_widget_class_add_action (widget_class, action);
12500}
12501
12502static const GVariantType *
12503determine_type (GParamSpec *pspec)
12504{
12505 if (G_TYPE_IS_ENUM (pspec->value_type))
12506 return G_VARIANT_TYPE_STRING;
12507
12508 switch (pspec->value_type)
12509 {
12510 case G_TYPE_BOOLEAN:
12511 return G_VARIANT_TYPE_BOOLEAN;
12512
12513 case G_TYPE_INT:
12514 return G_VARIANT_TYPE_INT32;
12515
12516 case G_TYPE_UINT:
12517 return G_VARIANT_TYPE_UINT32;
12518
12519 case G_TYPE_DOUBLE:
12520 case G_TYPE_FLOAT:
12521 return G_VARIANT_TYPE_DOUBLE;
12522
12523 case G_TYPE_STRING:
12524 return G_VARIANT_TYPE_STRING;
12525
12526 default:
12527 g_critical ("Unable to use gtk_widget_class_install_property_action with property '%s:%s' of type '%s'",
12528 g_type_name (pspec->owner_type), pspec->name, g_type_name (pspec->value_type));
12529 return NULL;
12530 }
12531}
12532
12533/**
12534 * gtk_widget_class_install_property_action:
12535 * @widget_class: a `GtkWidgetClass`
12536 * @action_name: name of the action
12537 * @property_name: name of the property in instances of @widget_class
12538 * or any parent class.
12539 *
12540 * Installs an action called @action_name on @widget_class and
12541 * binds its state to the value of the @property_name property.
12542 *
12543 * This function will perform a few santity checks on the property selected
12544 * via @property_name. Namely, the property must exist, must be readable,
12545 * writable and must not be construct-only. There are also restrictions
12546 * on the type of the given property, it must be boolean, int, unsigned int,
12547 * double or string. If any of these conditions are not met, a critical
12548 * warning will be printed and no action will be added.
12549 *
12550 * The state type of the action matches the property type.
12551 *
12552 * If the property is boolean, the action will have no parameter and
12553 * toggle the property value. Otherwise, the action will have a parameter
12554 * of the same type as the property.
12555 */
12556void
12557gtk_widget_class_install_property_action (GtkWidgetClass *widget_class,
12558 const char *action_name,
12559 const char *property_name)
12560{
12561 GParamSpec *pspec;
12562 GtkWidgetAction *action;
12563 const GVariantType *state_type;
12564
12565 g_return_if_fail (GTK_IS_WIDGET_CLASS (widget_class));
12566
12567 pspec = g_object_class_find_property (G_OBJECT_CLASS (widget_class), property_name);
12568
12569 if (pspec == NULL)
12570 {
12571 g_critical ("Attempted to use non-existent property '%s:%s' for gtk_widget_class_install_property_action",
12572 g_type_name (G_TYPE_FROM_CLASS (widget_class)), property_name);
12573 return;
12574 }
12575
12576 if (~pspec->flags & G_PARAM_READABLE || ~pspec->flags & G_PARAM_WRITABLE || pspec->flags & G_PARAM_CONSTRUCT_ONLY)
12577 {
12578 g_critical ("Property '%s:%s' used with gtk_widget_class_install_property_action must be readable, writable, and not construct-only",
12579 g_type_name (G_TYPE_FROM_CLASS (widget_class)), property_name);
12580 return;
12581 }
12582
12583 state_type = determine_type (pspec);
12584
12585 if (!state_type)
12586 return;
12587
12588 action = g_new0 (GtkWidgetAction, 1);
12589 action->owner = G_TYPE_FROM_CLASS (widget_class);
12590 action->name = g_strdup (str: action_name);
12591 action->pspec = pspec;
12592 action->state_type = state_type;
12593 if (action->pspec->value_type == G_TYPE_BOOLEAN)
12594 action->parameter_type = NULL;
12595 else
12596 action->parameter_type = action->state_type;
12597 action->activate = NULL;
12598
12599 gtk_widget_class_add_action (widget_class, action);
12600}
12601
12602/**
12603 * gtk_widget_action_set_enabled:
12604 * @widget: a `GtkWidget`
12605 * @action_name: action name, such as "clipboard.paste"
12606 * @enabled: whether the action is now enabled
12607 *
12608 * Enable or disable an action installed with
12609 * gtk_widget_class_install_action().
12610 */
12611void
12612gtk_widget_action_set_enabled (GtkWidget *widget,
12613 const char *action_name,
12614 gboolean enabled)
12615{
12616 GtkActionMuxer *muxer;
12617
12618 g_return_if_fail (GTK_IS_WIDGET (widget));
12619
12620 muxer = _gtk_widget_get_action_muxer (widget, TRUE);
12621 gtk_action_muxer_action_enabled_changed (muxer, action_name, enabled);
12622}
12623
12624/**
12625 * gtk_widget_class_query_action:
12626 * @widget_class: a `GtkWidget` class
12627 * @index_: position of the action to query
12628 * @owner: (out) (transfer none): return location for the type where the action was defined
12629 * @action_name: (out) (transfer none): return location for the action name
12630 * @parameter_type: (out) (transfer none) (nullable): return location for the parameter type
12631 * @property_name: (out) (transfer none) (nullable): return location for the property name
12632 *
12633 * Returns details about the @index_-th action that has been
12634 * installed for @widget_class during class initialization.
12635 *
12636 * See [method@Gtk.WidgetClass.install_action] for details on
12637 * how to install actions.
12638 *
12639 * Note that this function will also return actions defined
12640 * by parent classes. You can identify those by looking
12641 * at @owner.
12642 *
12643 * Returns: %TRUE if the action was found, %FALSE if @index_
12644 * is out of range
12645 */
12646gboolean
12647gtk_widget_class_query_action (GtkWidgetClass *widget_class,
12648 guint index_,
12649 GType *owner,
12650 const char **action_name,
12651 const GVariantType **parameter_type,
12652 const char **property_name)
12653{
12654 GtkWidgetClassPrivate *priv = widget_class->priv;
12655 GtkWidgetAction *action = priv->actions;
12656
12657 for (; index_ > 0 && action != NULL; index_--)
12658 action = action->next;
12659
12660 if (action != NULL && index_ == 0)
12661 {
12662 *owner = action->owner;
12663 *action_name = action->name;
12664 *parameter_type = action->parameter_type;
12665 if (action->pspec)
12666 *property_name = action->pspec->name;
12667 else
12668 *property_name = NULL;
12669
12670 return TRUE;
12671 }
12672
12673 return FALSE;
12674}
12675
12676/**
12677 * gtk_widget_get_css_name: (attributes org.gtk.Method.get_property=css-name)
12678 * @self: a `GtkWidget`
12679 *
12680 * Returns the CSS name that is used for @self.
12681 *
12682 * Returns: (transfer none): the CSS name
12683 */
12684const char *
12685gtk_widget_get_css_name (GtkWidget *self)
12686{
12687 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self);
12688
12689 g_return_val_if_fail (GTK_IS_WIDGET (self), NULL);
12690
12691 return g_quark_to_string (quark: gtk_css_node_get_name (cssnode: priv->cssnode));
12692}
12693
12694/**
12695 * gtk_widget_add_css_class:
12696 * @widget: a `GtkWidget`
12697 * @css_class: The style class to add to @widget, without
12698 * the leading '.' used for notation of style classes
12699 *
12700 * Adds a style class to @widget.
12701 *
12702 * After calling this function, the widgets style will match
12703 * for @css_class, according to CSS matching rules.
12704 *
12705 * Use [method@Gtk.Widget.remove_css_class] to remove the
12706 * style again.
12707 */
12708void
12709gtk_widget_add_css_class (GtkWidget *widget,
12710 const char *css_class)
12711{
12712 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
12713
12714 g_return_if_fail (GTK_IS_WIDGET (widget));
12715 g_return_if_fail (css_class != NULL);
12716 g_return_if_fail (css_class[0] != '\0');
12717 g_return_if_fail (css_class[0] != '.');
12718
12719 gtk_css_node_add_class (cssnode: priv->cssnode, style_class: g_quark_from_string (string: css_class));
12720 g_object_notify_by_pspec (G_OBJECT (widget), pspec: widget_props[PROP_CSS_CLASSES]);
12721}
12722
12723/**
12724 * gtk_widget_remove_css_class:
12725 * @widget: a `GtkWidget`
12726 * @css_class: The style class to remove from @widget, without
12727 * the leading '.' used for notation of style classes
12728 *
12729 * Removes a style from @widget.
12730 *
12731 * After this, the style of @widget will stop matching for @css_class.
12732 */
12733void
12734gtk_widget_remove_css_class (GtkWidget *widget,
12735 const char *css_class)
12736{
12737 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
12738 GQuark class_quark;
12739
12740 g_return_if_fail (GTK_IS_WIDGET (widget));
12741 g_return_if_fail (css_class != NULL);
12742 g_return_if_fail (css_class[0] != '\0');
12743 g_return_if_fail (css_class[0] != '.');
12744
12745 class_quark = g_quark_try_string (string: css_class);
12746 if (!class_quark)
12747 return;
12748
12749 gtk_css_node_remove_class (cssnode: priv->cssnode, style_class: class_quark);
12750 g_object_notify_by_pspec (G_OBJECT (widget), pspec: widget_props[PROP_CSS_CLASSES]);
12751}
12752
12753/**
12754 * gtk_widget_has_css_class:
12755 * @widget: a `GtkWidget`
12756 * @css_class: A style class, without the leading '.'
12757 * used for notation of style classes
12758 *
12759 * Returns whether @css_class is currently applied to @widget.
12760 *
12761 * Returns: %TRUE if @css_class is currently applied to @widget,
12762 * %FALSE otherwise.
12763 */
12764gboolean
12765gtk_widget_has_css_class (GtkWidget *widget,
12766 const char *css_class)
12767{
12768 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
12769 GQuark class_quark;
12770
12771 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
12772 g_return_val_if_fail (css_class != NULL, FALSE);
12773 g_return_val_if_fail (css_class[0] != '\0', FALSE);
12774 g_return_val_if_fail (css_class[0] != '.', FALSE);
12775
12776 class_quark = g_quark_try_string (string: css_class);
12777 if (!class_quark)
12778 return FALSE;
12779
12780 return gtk_css_node_has_class (cssnode: priv->cssnode, style_class: class_quark);
12781}
12782
12783/**
12784 * gtk_widget_get_css_classes: (attributes org.gtk.Method.get_property=css-classes)
12785 * @widget: a `GtkWidget`
12786 *
12787 * Returns the list of style classes applied to @widget.
12788 *
12789 * Returns: (transfer full): a %NULL-terminated list of
12790 * css classes currently applied to @widget. The returned
12791 * list must freed using g_strfreev().
12792 */
12793char **
12794gtk_widget_get_css_classes (GtkWidget *widget)
12795{
12796 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
12797 const GQuark *classes;
12798 guint n_classes;
12799 char **strv;
12800 guint i;
12801
12802 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
12803
12804 classes = gtk_css_node_list_classes (cssnode: priv->cssnode, n_classes: &n_classes);
12805 strv = g_new (char *, n_classes + 1);
12806
12807 for (i = 0; i < n_classes; i++)
12808 strv[i] = g_strdup (str: g_quark_to_string (quark: classes[i]));
12809
12810 strv[n_classes] = NULL;
12811
12812 return strv;
12813}
12814
12815/**
12816 * gtk_widget_set_css_classes: (attributes org.gtk.Method.set_property=css-classes)
12817 * @widget: a `GtkWidget`
12818 * @classes: (transfer none) (array zero-terminated=1):
12819 * %NULL-terminated list of style classes to apply to @widget.
12820 *
12821 * Clear all style classes applied to @widget
12822 * and replace them with @classes.
12823 */
12824void
12825gtk_widget_set_css_classes (GtkWidget *widget,
12826 const char **classes)
12827{
12828 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
12829
12830 g_return_if_fail (GTK_IS_WIDGET (widget));
12831
12832 gtk_css_node_set_classes (cssnode: priv->cssnode, classes);
12833 g_object_notify_by_pspec (G_OBJECT (widget), pspec: widget_props[PROP_CSS_CLASSES]);
12834}
12835
12836/*< private >
12837 * gtk_widget_update_orientation:
12838 * @widget: a `GtkWidget` implementing `GtkOrientable`
12839 * @orientation: the orientation
12840 *
12841 * Update the internal state associated to the given
12842 * @orientation of a `GtkWidget`.
12843 */
12844void
12845gtk_widget_update_orientation (GtkWidget *widget,
12846 GtkOrientation orientation)
12847{
12848 g_return_if_fail (GTK_IS_WIDGET (widget));
12849
12850 if (orientation == GTK_ORIENTATION_HORIZONTAL)
12851 {
12852 gtk_widget_add_css_class (widget, css_class: "horizontal");
12853 gtk_widget_remove_css_class (widget, css_class: "vertical");
12854 }
12855 else
12856 {
12857 gtk_widget_add_css_class (widget, css_class: "vertical");
12858 gtk_widget_remove_css_class (widget, css_class: "horizontal");
12859 }
12860
12861 gtk_accessible_update_property (self: GTK_ACCESSIBLE (ptr: widget),
12862 first_property: GTK_ACCESSIBLE_PROPERTY_ORIENTATION, orientation,
12863 -1);
12864}
12865
12866/**
12867 * gtk_widget_class_set_accessible_role:
12868 * @widget_class: a `GtkWidgetClass`
12869 * @accessible_role: the `GtkAccessibleRole` used by the @widget_class
12870 *
12871 * Sets the accessible role used by the given `GtkWidget` class.
12872 *
12873 * Different accessible roles have different states, and are
12874 * rendered differently by assistive technologies.
12875 */
12876void
12877gtk_widget_class_set_accessible_role (GtkWidgetClass *widget_class,
12878 GtkAccessibleRole accessible_role)
12879{
12880 GtkWidgetClassPrivate *priv;
12881
12882 g_return_if_fail (GTK_IS_WIDGET_CLASS (widget_class));
12883
12884 priv = widget_class->priv;
12885 priv->accessible_role = accessible_role;
12886}
12887
12888/**
12889 * gtk_widget_class_get_accessible_role:
12890 * @widget_class: a `GtkWidgetClass`
12891 *
12892 * Retrieves the accessible role used by the given `GtkWidget` class.
12893 *
12894 * Different accessible roles have different states, and are rendered
12895 * differently by assistive technologies.
12896 *
12897 * See also: [method@Gtk.Accessible.get_accessible_role].
12898 *
12899 * Returns: the accessible role for the widget class
12900 */
12901GtkAccessibleRole
12902gtk_widget_class_get_accessible_role (GtkWidgetClass *widget_class)
12903{
12904 GtkWidgetClassPrivate *priv;
12905
12906 g_return_val_if_fail (GTK_IS_WIDGET_CLASS (widget_class), GTK_ACCESSIBLE_ROLE_WIDGET);
12907
12908 priv = widget_class->priv;
12909 return priv->accessible_role;
12910}
12911
12912void
12913gtk_widget_set_active_state (GtkWidget *widget,
12914 gboolean active)
12915{
12916 GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self: widget);
12917
12918 if (active)
12919 {
12920 priv->n_active++;
12921 gtk_widget_set_state_flags (widget, flags: GTK_STATE_FLAG_ACTIVE, FALSE);
12922 }
12923 else
12924 {
12925 if (priv->n_active == 0)
12926 {
12927 g_warning ("Broken accounting of active state for widget %p(%s)",
12928 widget, G_OBJECT_TYPE_NAME (widget));
12929 }
12930 else
12931 priv->n_active--;
12932
12933 if (priv->n_active == 0)
12934 gtk_widget_unset_state_flags (widget, flags: GTK_STATE_FLAG_ACTIVE);
12935 }
12936}
12937

source code of gtk/gtk/gtkwidget.c