diff options
author | Matthias Clasen <mclasen@redhat.com> | 2021-01-05 15:20:25 +0000 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2021-01-05 15:20:25 +0000 |
commit | b79c26b39efa854c7464df81d3aaed2b2c9bece5 (patch) | |
tree | d05dd9450154a160d3083a06db695483414d652c | |
parent | 7c5b8911d80bd07f7e0f54a05df4da7844687db5 (diff) | |
parent | 42fedfc87030361c502ff68cf46bbb6924099e08 (diff) | |
download | gtk+-b79c26b39efa854c7464df81d3aaed2b2c9bece5.tar.gz |
Merge branch 'wip/baedert/for-master' into 'master'
Wip/baedert/for master
See merge request GNOME/gtk!3029
-rw-r--r-- | demos/widget-factory/widget-factory.ui | 1 | ||||
-rw-r--r-- | gdk/wayland/gdkglcontext-wayland.c | 69 | ||||
-rw-r--r-- | gtk/css/gtkcsstokenizer.c | 198 | ||||
-rw-r--r-- | gtk/gtkbox.c | 6 | ||||
-rw-r--r-- | gtk/gtkbuilderparser.c | 52 | ||||
-rw-r--r-- | gtk/gtkbuilderprivate.h | 7 | ||||
-rw-r--r-- | gtk/gtkframe.c | 15 | ||||
-rw-r--r-- | gtk/gtkgesture.c | 2 | ||||
-rw-r--r-- | gtk/gtkgesturelongpress.c | 28 | ||||
-rw-r--r-- | gtk/gtkgesturestylus.c | 26 | ||||
-rw-r--r-- | gtk/gtkicontheme.c | 2 | ||||
-rw-r--r-- | gtk/gtklabel.c | 3878 | ||||
-rw-r--r-- | gtk/gtklabelprivate.h | 18 | ||||
-rw-r--r-- | gtk/gtkmessagedialog.c | 522 | ||||
-rw-r--r-- | gtk/gtkrender.c | 43 | ||||
-rw-r--r-- | gtk/gtkscrolledwindow.c | 39 | ||||
-rw-r--r-- | gtk/gtksettings.c | 38 | ||||
-rw-r--r-- | gtk/gtkshortcutmanager.c | 17 | ||||
-rw-r--r-- | gtk/gtkshortcuttrigger.c | 3 | ||||
-rw-r--r-- | gtk/gtkviewport.c | 6 | ||||
-rw-r--r-- | gtk/gtkwidget.c | 1469 |
21 files changed, 3001 insertions, 3438 deletions
diff --git a/demos/widget-factory/widget-factory.ui b/demos/widget-factory/widget-factory.ui index 5532619bc1..306cbbac42 100644 --- a/demos/widget-factory/widget-factory.ui +++ b/demos/widget-factory/widget-factory.ui @@ -3298,7 +3298,6 @@ bad things might happen.</property> </object> </child> </object> - <object class="GtkSizeGroup" id="basement-indicators"/> <menu id="new_style_menu_model"> <section> <attribute name="display-hint">circular-buttons</attribute> diff --git a/gdk/wayland/gdkglcontext-wayland.c b/gdk/wayland/gdkglcontext-wayland.c index a668731196..a5939416f8 100644 --- a/gdk/wayland/gdkglcontext-wayland.c +++ b/gdk/wayland/gdkglcontext-wayland.c @@ -242,14 +242,22 @@ gdk_wayland_gl_context_end_frame (GdkDrawContext *draw_context, gdk_profiler_add_mark (GDK_PROFILER_CURRENT_TIME, 0, "wayland", "swap buffers"); if (display_wayland->have_egl_swap_buffers_with_damage) { + EGLint stack_rects[4 * 4]; /* 4 rects */ + EGLint *heap_rects = NULL; int i, j, n_rects = cairo_region_num_rectangles (painted); - EGLint *rects = g_new (EGLint, n_rects * 4); - cairo_rectangle_int_t rect; int surface_height = gdk_surface_get_height (surface); int scale = gdk_surface_get_scale_factor (surface); + EGLint *rects; + + if (n_rects < G_N_ELEMENTS (stack_rects) / 4) + rects = (EGLint *)&stack_rects; + else + heap_rects = rects = g_new (EGLint, n_rects * 4); for (i = 0, j = 0; i < n_rects; i++) { + cairo_rectangle_int_t rect; + cairo_region_get_rectangle (painted, i, &rect); rects[j++] = rect.x * scale; rects[j++] = (surface_height - rect.height - rect.y) * scale; @@ -257,7 +265,7 @@ gdk_wayland_gl_context_end_frame (GdkDrawContext *draw_context, rects[j++] = rect.height * scale; } eglSwapBuffersWithDamageEXT (display_wayland->egl_display, egl_surface, rects, n_rects); - g_free (rects); + g_free (heap_rects); } else eglSwapBuffers (display_wayland->egl_display, egl_surface); @@ -293,27 +301,27 @@ gdk_wayland_get_display (GdkWaylandDisplay *display_wayland) if (epoxy_has_egl_extension (NULL, "EGL_KHR_platform_base")) { PFNEGLGETPLATFORMDISPLAYPROC getPlatformDisplay = - (void *) eglGetProcAddress ("eglGetPlatformDisplay"); + (void *) eglGetProcAddress ("eglGetPlatformDisplay"); if (getPlatformDisplay) - dpy = getPlatformDisplay (EGL_PLATFORM_WAYLAND_EXT, - display_wayland->wl_display, - NULL); + dpy = getPlatformDisplay (EGL_PLATFORM_WAYLAND_EXT, + display_wayland->wl_display, + NULL); if (dpy) - return dpy; + return dpy; } if (epoxy_has_egl_extension (NULL, "EGL_EXT_platform_base")) { PFNEGLGETPLATFORMDISPLAYEXTPROC getPlatformDisplay = - (void *) eglGetProcAddress ("eglGetPlatformDisplayEXT"); + (void *) eglGetProcAddress ("eglGetPlatformDisplayEXT"); if (getPlatformDisplay) - dpy = getPlatformDisplay (EGL_PLATFORM_WAYLAND_EXT, - display_wayland->wl_display, - NULL); + dpy = getPlatformDisplay (EGL_PLATFORM_WAYLAND_EXT, + display_wayland->wl_display, + NULL); if (dpy) - return dpy; + return dpy; } return eglGetDisplay ((EGLNativeDisplayType) display_wayland->wl_display); @@ -386,7 +394,7 @@ find_eglconfig_for_surface (GdkSurface *surface, GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display); EGLint attrs[MAX_EGL_ATTRS]; EGLint count; - EGLConfig *configs; + EGLConfig config; int i = 0; attrs[i++] = EGL_SURFACE_TYPE; @@ -407,17 +415,8 @@ find_eglconfig_for_surface (GdkSurface *surface, attrs[i++] = EGL_NONE; g_assert (i < MAX_EGL_ATTRS); - if (!eglChooseConfig (display_wayland->egl_display, attrs, NULL, 0, &count) || count < 1) - { - g_set_error_literal (error, GDK_GL_ERROR, - GDK_GL_ERROR_UNSUPPORTED_FORMAT, - _("No available configurations for the given pixel format")); - return FALSE; - } - - configs = g_new (EGLConfig, count); - - if (!eglChooseConfig (display_wayland->egl_display, attrs, configs, count, &count) || count < 1) + /* Pick first valid configuration i guess? */ + if (!eglChooseConfig (display_wayland->egl_display, attrs, &config, 1, &count) || count < 1) { g_set_error_literal (error, GDK_GL_ERROR, GDK_GL_ERROR_UNSUPPORTED_FORMAT, @@ -425,21 +424,17 @@ find_eglconfig_for_surface (GdkSurface *surface, return FALSE; } - /* Pick first valid configuration i guess? */ - - if (egl_config_out != NULL) - *egl_config_out = configs[0]; - - g_free (configs); + g_assert (egl_config_out); + *egl_config_out = config; return TRUE; } GdkGLContext * gdk_wayland_surface_create_gl_context (GdkSurface *surface, - gboolean attached, - GdkGLContext *share, - GError **error) + gboolean attached, + GdkGLContext *share, + GError **error) { GdkDisplay *display = gdk_surface_get_display (surface); GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display); @@ -526,10 +521,10 @@ gdk_wayland_display_make_gl_context_current (GdkDisplay *display, else { if (display_wayland->have_egl_surfaceless_context) - egl_surface = EGL_NO_SURFACE; + egl_surface = EGL_NO_SURFACE; else - egl_surface = gdk_wayland_surface_get_dummy_egl_surface (surface, - context_wayland->egl_config); + egl_surface = gdk_wayland_surface_get_dummy_egl_surface (surface, + context_wayland->egl_config); } if (!eglMakeCurrent (display_wayland->egl_display, egl_surface, diff --git a/gtk/css/gtkcsstokenizer.c b/gtk/css/gtkcsstokenizer.c index 203d7f3a45..a406ad3d06 100644 --- a/gtk/css/gtkcsstokenizer.c +++ b/gtk/css/gtkcsstokenizer.c @@ -30,6 +30,7 @@ struct _GtkCssTokenizer { int ref_count; GBytes *bytes; + GString *name_buffer; const char *data; const char *end; @@ -95,45 +96,13 @@ gtk_css_token_clear (GtkCssToken *token) } static void -gtk_css_token_initv (GtkCssToken *token, - GtkCssTokenType type, - va_list args) +gtk_css_token_init (GtkCssToken *token, + GtkCssTokenType type) { token->type = type; - switch (type) + switch ((guint)type) { - case GTK_CSS_TOKEN_STRING: - case GTK_CSS_TOKEN_IDENT: - case GTK_CSS_TOKEN_FUNCTION: - case GTK_CSS_TOKEN_AT_KEYWORD: - case GTK_CSS_TOKEN_HASH_UNRESTRICTED: - case GTK_CSS_TOKEN_HASH_ID: - case GTK_CSS_TOKEN_URL: - token->string.string = va_arg (args, char *); - break; - - case GTK_CSS_TOKEN_DELIM: - token->delim.delim = va_arg (args, gunichar); - break; - - case GTK_CSS_TOKEN_SIGNED_INTEGER: - case GTK_CSS_TOKEN_SIGNLESS_INTEGER: - case GTK_CSS_TOKEN_SIGNED_NUMBER: - case GTK_CSS_TOKEN_SIGNLESS_NUMBER: - case GTK_CSS_TOKEN_PERCENTAGE: - token->number.number = va_arg (args, double); - break; - - case GTK_CSS_TOKEN_SIGNED_INTEGER_DIMENSION: - case GTK_CSS_TOKEN_SIGNLESS_INTEGER_DIMENSION: - case GTK_CSS_TOKEN_DIMENSION: - token->dimension.value = va_arg (args, double); - token->dimension.dimension = va_arg (args, char *); - break; - - default: - g_assert_not_reached (); case GTK_CSS_TOKEN_EOF: case GTK_CSS_TOKEN_WHITESPACE: case GTK_CSS_TOKEN_OPEN_PARENS: @@ -157,6 +126,8 @@ gtk_css_token_initv (GtkCssToken *token, case GTK_CSS_TOKEN_BAD_URL: case GTK_CSS_TOKEN_COMMENT: break; + default: + g_assert_not_reached (); } } @@ -515,15 +486,76 @@ gtk_css_token_to_string (const GtkCssToken *token) } static void -gtk_css_token_init (GtkCssToken *token, - GtkCssTokenType type, - ...) +gtk_css_token_init_string (GtkCssToken *token, + GtkCssTokenType type, + char *string) { - va_list args; + token->type = type; - va_start (args, type); - gtk_css_token_initv (token, type, args); - va_end (args); + switch ((guint)type) + { + case GTK_CSS_TOKEN_STRING: + case GTK_CSS_TOKEN_IDENT: + case GTK_CSS_TOKEN_FUNCTION: + case GTK_CSS_TOKEN_AT_KEYWORD: + case GTK_CSS_TOKEN_HASH_UNRESTRICTED: + case GTK_CSS_TOKEN_HASH_ID: + case GTK_CSS_TOKEN_URL: + token->string.string = string; + break; + default: + g_assert_not_reached (); + } +} + +static void +gtk_css_token_init_delim (GtkCssToken *token, + gunichar delim) +{ + token->type = GTK_CSS_TOKEN_DELIM; + token->delim.delim = delim; +} + +static void +gtk_css_token_init_number (GtkCssToken *token, + GtkCssTokenType type, + double value) +{ + token->type = type; + + switch ((guint)type) + { + case GTK_CSS_TOKEN_SIGNED_INTEGER: + case GTK_CSS_TOKEN_SIGNLESS_INTEGER: + case GTK_CSS_TOKEN_SIGNED_NUMBER: + case GTK_CSS_TOKEN_SIGNLESS_NUMBER: + case GTK_CSS_TOKEN_PERCENTAGE: + token->number.number = value; + break; + default: + g_assert_not_reached (); + } +} + +static void +gtk_css_token_init_dimension (GtkCssToken *token, + GtkCssTokenType type, + double value, + char *dimension) +{ + token->type = type; + + switch ((guint)type) + { + case GTK_CSS_TOKEN_SIGNED_INTEGER_DIMENSION: + case GTK_CSS_TOKEN_SIGNLESS_INTEGER_DIMENSION: + case GTK_CSS_TOKEN_DIMENSION: + token->dimension.value = value; + token->dimension.dimension = dimension; + break; + default: + g_assert_not_reached (); + } } GtkCssTokenizer * @@ -534,6 +566,7 @@ gtk_css_tokenizer_new (GBytes *bytes) tokenizer = g_slice_new0 (GtkCssTokenizer); tokenizer->ref_count = 1; tokenizer->bytes = g_bytes_ref (bytes); + tokenizer->name_buffer = g_string_new (NULL); tokenizer->data = g_bytes_get_data (bytes, NULL); tokenizer->end = tokenizer->data + g_bytes_get_size (bytes); @@ -558,6 +591,7 @@ gtk_css_tokenizer_unref (GtkCssTokenizer *tokenizer) if (tokenizer->ref_count > 0) return; + g_string_free (tokenizer->name_buffer, TRUE); g_bytes_unref (tokenizer->bytes); g_slice_free (GtkCssTokenizer, tokenizer); } @@ -568,11 +602,7 @@ gtk_css_tokenizer_get_location (GtkCssTokenizer *tokenizer) return &tokenizer->position; } -static void -gtk_css_tokenizer_parse_error (GError **error, - const char *format, - ...) G_GNUC_PRINTF(2, 3); -static void +static void G_GNUC_PRINTF(2, 3) gtk_css_tokenizer_parse_error (GError **error, const char *format, ...) @@ -843,7 +873,7 @@ gtk_css_tokenizer_read_escape (GtkCssTokenizer *tokenizer) static char * gtk_css_tokenizer_read_name (GtkCssTokenizer *tokenizer) { - GString *string = g_string_new (NULL); + g_string_set_size (tokenizer->name_buffer, 0); do { if (*tokenizer->data == '\\') @@ -851,7 +881,7 @@ gtk_css_tokenizer_read_name (GtkCssTokenizer *tokenizer) if (gtk_css_tokenizer_has_valid_escape (tokenizer)) { gunichar value = gtk_css_tokenizer_read_escape (tokenizer); - g_string_append_unichar (string, value); + g_string_append_unichar (tokenizer->name_buffer, value); } else { @@ -859,16 +889,16 @@ gtk_css_tokenizer_read_name (GtkCssTokenizer *tokenizer) if (tokenizer->data == tokenizer->end) { - g_string_append_unichar (string, 0xFFFD); + g_string_append_unichar (tokenizer->name_buffer, 0xFFFD); break; } - gtk_css_tokenizer_consume_char (tokenizer, string); + gtk_css_tokenizer_consume_char (tokenizer, tokenizer->name_buffer); } } else if (is_name (*tokenizer->data)) { - gtk_css_tokenizer_consume_char (tokenizer, string); + gtk_css_tokenizer_consume_char (tokenizer, tokenizer->name_buffer); } else { @@ -877,7 +907,7 @@ gtk_css_tokenizer_read_name (GtkCssTokenizer *tokenizer) } while (tokenizer->data != tokenizer->end); - return g_string_free (string, FALSE); + return g_strndup (tokenizer->name_buffer->str, tokenizer->name_buffer->len); } static void @@ -970,7 +1000,7 @@ gtk_css_tokenizer_read_url (GtkCssTokenizer *tokenizer, } } - gtk_css_token_init (token, GTK_CSS_TOKEN_URL, g_string_free (url, FALSE)); + gtk_css_token_init_string (token, GTK_CSS_TOKEN_URL, g_string_free (url, FALSE)); return TRUE; } @@ -999,12 +1029,12 @@ gtk_css_tokenizer_read_ident_like (GtkCssTokenizer *tokenizer, } } - gtk_css_token_init (token, GTK_CSS_TOKEN_FUNCTION, name); + gtk_css_token_init_string (token, GTK_CSS_TOKEN_FUNCTION, name); return TRUE; } else { - gtk_css_token_init (token, GTK_CSS_TOKEN_IDENT, name); + gtk_css_token_init_string (token, GTK_CSS_TOKEN_IDENT, name); return TRUE; } } @@ -1017,6 +1047,7 @@ gtk_css_tokenizer_read_numeric (GtkCssTokenizer *tokenizer, gint64 integer, fractional = 0, fractional_length = 1, exponent = 0; gboolean is_int = TRUE, has_sign = FALSE; const char *data = tokenizer->data; + double value; if (*data == '-') { @@ -1082,27 +1113,34 @@ gtk_css_tokenizer_read_numeric (GtkCssTokenizer *tokenizer, gtk_css_tokenizer_consume (tokenizer, data - tokenizer->data, data - tokenizer->data); + value = sign * (integer + ((double) fractional / fractional_length)) * pow (10, exponent_sign * exponent); + if (gtk_css_tokenizer_has_identifier (tokenizer)) { - gtk_css_token_init (token, - is_int ? (has_sign ? GTK_CSS_TOKEN_SIGNED_INTEGER_DIMENSION : GTK_CSS_TOKEN_SIGNLESS_INTEGER_DIMENSION) - : GTK_CSS_TOKEN_DIMENSION, - sign * (integer + ((double) fractional / fractional_length)) * pow (10, exponent_sign * exponent), - gtk_css_tokenizer_read_name (tokenizer)); + GtkCssTokenType type; + + if (is_int) + type = has_sign ? GTK_CSS_TOKEN_SIGNED_INTEGER_DIMENSION : GTK_CSS_TOKEN_SIGNLESS_INTEGER_DIMENSION; + else + type = GTK_CSS_TOKEN_DIMENSION; + + gtk_css_token_init_dimension (token, type, value, gtk_css_tokenizer_read_name (tokenizer)); } else if (gtk_css_tokenizer_remaining (tokenizer) > 0 && *tokenizer->data == '%') { - gtk_css_token_init (token, - GTK_CSS_TOKEN_PERCENTAGE, - sign * (integer + ((double) fractional / fractional_length)) * pow (10, exponent_sign * exponent)); + gtk_css_token_init_number (token, GTK_CSS_TOKEN_PERCENTAGE, value); gtk_css_tokenizer_consume_ascii (tokenizer); } else { - gtk_css_token_init (token, - is_int ? (has_sign ? GTK_CSS_TOKEN_SIGNED_INTEGER : GTK_CSS_TOKEN_SIGNLESS_INTEGER) - : (has_sign ? GTK_CSS_TOKEN_SIGNED_NUMBER : GTK_CSS_TOKEN_SIGNLESS_NUMBER), - sign * (integer + ((double) fractional / fractional_length)) * pow (10, exponent_sign * exponent)); + GtkCssTokenType type; + + if (is_int) + type = has_sign ? GTK_CSS_TOKEN_SIGNED_INTEGER : GTK_CSS_TOKEN_SIGNLESS_INTEGER; + else + type = has_sign ? GTK_CSS_TOKEN_SIGNED_NUMBER : GTK_CSS_TOKEN_SIGNLESS_NUMBER; + + gtk_css_token_init_number (token, type,value); } } @@ -1110,7 +1148,7 @@ static void gtk_css_tokenizer_read_delim (GtkCssTokenizer *tokenizer, GtkCssToken *token) { - gtk_css_token_init (token, GTK_CSS_TOKEN_DELIM, g_utf8_get_char (tokenizer->data)); + gtk_css_token_init_delim (token, g_utf8_get_char (tokenizer->data)); gtk_css_tokenizer_consume_char (tokenizer, NULL); } @@ -1194,8 +1232,8 @@ gtk_css_tokenizer_read_string (GtkCssTokenizer *tokenizer, gtk_css_tokenizer_consume_char (tokenizer, string); } } - - gtk_css_token_init (token, GTK_CSS_TOKEN_STRING, g_string_free (string, FALSE)); + + gtk_css_token_init_string (token, GTK_CSS_TOKEN_STRING, g_string_free (string, FALSE)); return TRUE; } @@ -1279,13 +1317,13 @@ gtk_css_tokenizer_read_token (GtkCssTokenizer *tokenizer, else type = GTK_CSS_TOKEN_HASH_UNRESTRICTED; - gtk_css_token_init (token, - type, - gtk_css_tokenizer_read_name (tokenizer)); + gtk_css_token_init_string (token, + type, + gtk_css_tokenizer_read_name (tokenizer)); } else { - gtk_css_token_init (token, GTK_CSS_TOKEN_DELIM, '#'); + gtk_css_token_init_delim (token, '#'); } return TRUE; @@ -1361,13 +1399,13 @@ gtk_css_tokenizer_read_token (GtkCssTokenizer *tokenizer, gtk_css_tokenizer_consume_ascii (tokenizer); if (gtk_css_tokenizer_has_identifier (tokenizer)) { - gtk_css_token_init (token, - GTK_CSS_TOKEN_AT_KEYWORD, - gtk_css_tokenizer_read_name (tokenizer)); + gtk_css_token_init_string (token, + GTK_CSS_TOKEN_AT_KEYWORD, + gtk_css_tokenizer_read_name (tokenizer)); } else { - gtk_css_token_init (token, GTK_CSS_TOKEN_DELIM, '@'); + gtk_css_token_init_delim (token, '@'); } return TRUE; @@ -1383,7 +1421,7 @@ gtk_css_tokenizer_read_token (GtkCssTokenizer *tokenizer, } else { - gtk_css_token_init (token, GTK_CSS_TOKEN_DELIM, '\\'); + gtk_css_token_init_delim (token, '\\'); gtk_css_tokenizer_consume_ascii (tokenizer); gtk_css_tokenizer_parse_error (error, "Newline may not follow '\' escape character"); return FALSE; diff --git a/gtk/gtkbox.c b/gtk/gtkbox.c index f59595a3b0..074d98d2a3 100644 --- a/gtk/gtkbox.c +++ b/gtk/gtkbox.c @@ -346,7 +346,7 @@ gtk_box_new (GtkOrientation orientation, */ void gtk_box_set_homogeneous (GtkBox *box, - gboolean homogeneous) + gboolean homogeneous) { GtkBoxLayout *box_layout; @@ -393,7 +393,7 @@ gtk_box_get_homogeneous (GtkBox *box) */ void gtk_box_set_spacing (GtkBox *box, - int spacing) + int spacing) { GtkBoxLayout *box_layout; @@ -441,7 +441,7 @@ gtk_box_get_spacing (GtkBox *box) */ void gtk_box_set_baseline_position (GtkBox *box, - GtkBaselinePosition position) + GtkBaselinePosition position) { GtkBoxLayout *box_layout; diff --git a/gtk/gtkbuilderparser.c b/gtk/gtkbuilderparser.c index b714a8e869..41935df8e1 100644 --- a/gtk/gtkbuilderparser.c +++ b/gtk/gtkbuilderparser.c @@ -365,16 +365,17 @@ static void free_object_info (ObjectInfo *info); static inline void state_push (ParserData *data, gpointer info) { - data->stack = g_slist_prepend (data->stack, info); + g_ptr_array_add (data->stack, info); } static inline gpointer state_peek (ParserData *data) { - if (!data->stack) + if (!data->stack || + data->stack->len == 0) return NULL; - return data->stack->data; + return g_ptr_array_index (data->stack, data->stack->len - 1); } static inline gpointer @@ -384,8 +385,9 @@ state_pop (ParserData *data) g_assert (data->stack); - old = data->stack->data; - data->stack = g_slist_delete_link (data->stack, data->stack); + old = state_peek (data); + g_assert (old); + data->stack->len --; return old; } #define state_peek_info(data, st) ((st*)state_peek(data)) @@ -2077,7 +2079,7 @@ text (GtkBuildableParseContext *context, return; } - if (!data->stack) + if (!data->stack || data->stack->len == 0) return; info = state_peek_info (data, CommonInfo); @@ -2118,41 +2120,6 @@ text (GtkBuildableParseContext *context, } } -static void -free_info (CommonInfo *info) -{ - switch (info->tag_type) - { - case TAG_OBJECT: - case TAG_TEMPLATE: - free_object_info ((ObjectInfo *)info); - break; - case TAG_CHILD: - free_child_info ((ChildInfo *)info); - break; - case TAG_BINDING: - _free_binding_info ((BindingInfo *)info, NULL); - break; - case TAG_BINDING_EXPRESSION: - free_binding_expression_info ((BindingExpressionInfo *) info); - break; - case TAG_PROPERTY: - free_property_info ((PropertyInfo *)info); - break; - case TAG_SIGNAL: - _free_signal_info ((SignalInfo *)info, NULL); - break; - case TAG_REQUIRES: - free_requires_info ((RequiresInfo *)info, NULL); - break; - case TAG_EXPRESSION: - free_expression_info ((ExpressionInfo *)info); - break; - default: - g_assert_not_reached (); - } -} - static const GtkBuildableParser parser = { start_element, end_element, @@ -2186,6 +2153,7 @@ _gtk_builder_parser_parse_buffer (GtkBuilder *builder, data.domain = g_strdup (domain); data.object_ids = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify)g_free, NULL); + data.stack = g_ptr_array_new (); if (requested_objs) { @@ -2237,11 +2205,11 @@ _gtk_builder_parser_parse_buffer (GtkBuilder *builder, out: - g_slist_free_full (data.stack, (GDestroyNotify)free_info); g_slist_free_full (data.custom_finalizers, (GDestroyNotify)free_subparser); g_slist_free (data.finalizers); g_free (data.domain); g_hash_table_destroy (data.object_ids); + g_ptr_array_free (data.stack, TRUE); gtk_buildable_parse_context_free (&data.ctx); /* restore the original domain */ diff --git a/gtk/gtkbuilderprivate.h b/gtk/gtkbuilderprivate.h index c6200685c4..74c688b2de 100644 --- a/gtk/gtkbuilderprivate.h +++ b/gtk/gtkbuilderprivate.h @@ -173,7 +173,7 @@ typedef struct { const char *last_element; GtkBuilder *builder; char *domain; - GSList *stack; + GPtrArray *stack; SubParser *subparser; GtkBuildableParseContext ctx; const char *filename; @@ -190,8 +190,6 @@ typedef struct { GHashTable *object_ids; } ParserData; -typedef GType (*GTypeGetFunc) (void); - /* Things only GtkBuilder should use */ GBytes * _gtk_buildable_parser_precompile (const char *text, gssize text_len, @@ -286,8 +284,5 @@ GObject *_gtk_builder_lookup_object (GtkBuilder *builder, int col); gboolean _gtk_builder_lookup_failed (GtkBuilder *builder, GError **error); -GModule *gtk_builder_get_module (GtkBuilder *builder); - - #endif /* __GTK_BUILDER_PRIVATE_H__ */ diff --git a/gtk/gtkframe.c b/gtk/gtkframe.c index a8aa980779..10b9c818d4 100644 --- a/gtk/gtkframe.c +++ b/gtk/gtkframe.c @@ -114,9 +114,6 @@ static void gtk_frame_size_allocate (GtkWidget *widget, int width, int height, int baseline); - -static void gtk_frame_compute_child_allocation (GtkFrame *frame, - GtkAllocation *child_allocation); static void gtk_frame_real_compute_child_allocation (GtkFrame *frame, GtkAllocation *child_allocation); @@ -497,7 +494,7 @@ gtk_frame_size_allocate (GtkWidget *widget, GtkFramePrivate *priv = gtk_frame_get_instance_private (frame); GtkAllocation new_allocation; - gtk_frame_compute_child_allocation (frame, &new_allocation); + GTK_FRAME_GET_CLASS (frame)->compute_child_allocation (frame, &new_allocation); if (priv->label_widget && gtk_widget_get_visible (priv->label_widget)) @@ -530,16 +527,6 @@ gtk_frame_size_allocate (GtkWidget *widget, } static void -gtk_frame_compute_child_allocation (GtkFrame *frame, - GtkAllocation *child_allocation) -{ - g_return_if_fail (GTK_IS_FRAME (frame)); - g_return_if_fail (child_allocation != NULL); - - GTK_FRAME_GET_CLASS (frame)->compute_child_allocation (frame, child_allocation); -} - -static void gtk_frame_real_compute_child_allocation (GtkFrame *frame, GtkAllocation *child_allocation) { diff --git a/gtk/gtkgesture.c b/gtk/gtkgesture.c index f0bb28421a..802309c43d 100644 --- a/gtk/gtkgesture.c +++ b/gtk/gtkgesture.c @@ -759,7 +759,7 @@ gtk_gesture_class_init (GtkGestureClass *klass) "to trigger the gesture"), 1, G_MAXUINT, 1, GTK_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY)); + G_PARAM_CONSTRUCT_ONLY)); /** * GtkGesture::begin: * @gesture: the object which received the signal diff --git a/gtk/gtkgesturelongpress.c b/gtk/gtkgesturelongpress.c index df01077ab4..7a27a307fc 100644 --- a/gtk/gtkgesturelongpress.c +++ b/gtk/gtkgesturelongpress.c @@ -51,7 +51,8 @@ enum { }; enum { - PROP_DELAY_FACTOR = 1 + PROP_DELAY_FACTOR = 1, + LAST_PROP }; struct _GtkGestureLongPressPrivate @@ -67,15 +68,14 @@ struct _GtkGestureLongPressPrivate }; static guint signals[N_SIGNALS] = { 0 }; +static GParamSpec *props[LAST_PROP] = { NULL, }; G_DEFINE_TYPE_WITH_PRIVATE (GtkGestureLongPress, gtk_gesture_long_press, GTK_TYPE_GESTURE_SINGLE) static void gtk_gesture_long_press_init (GtkGestureLongPress *gesture) { - GtkGestureLongPressPrivate *priv; - - priv = gtk_gesture_long_press_get_instance_private (GTK_GESTURE_LONG_PRESS (gesture)); + GtkGestureLongPressPrivate *priv = gtk_gesture_long_press_get_instance_private (gesture); priv->delay_factor = 1.0; } @@ -275,13 +275,14 @@ gtk_gesture_long_press_class_init (GtkGestureLongPressClass *klass) gesture_class->cancel = gtk_gesture_long_press_cancel; gesture_class->sequence_state_changed = gtk_gesture_long_press_sequence_state_changed; - g_object_class_install_property (object_class, - PROP_DELAY_FACTOR, - g_param_spec_double ("delay-factor", - P_("Delay factor"), - P_("Factor by which to modify the default timeout"), - 0.5, 2.0, 1.0, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY)); + props[PROP_DELAY_FACTOR] = + g_param_spec_double ("delay-factor", + P_("Delay factor"), + P_("Factor by which to modify the default timeout"), + 0.5, 2.0, 1.0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + + g_object_class_install_properties (object_class, LAST_PROP, props); /** * GtkGestureLongPress::pressed: @@ -351,9 +352,12 @@ gtk_gesture_long_press_set_delay_factor (GtkGestureLongPress *gesture, g_return_if_fail (delay_factor >= 0.5); g_return_if_fail (delay_factor <= 2.0); + if (delay_factor == priv->delay_factor) + return; + priv->delay_factor = delay_factor; - g_object_notify (G_OBJECT (gesture), "delay-factor"); + g_object_notify_by_pspec (G_OBJECT (gesture), props[PROP_DELAY_FACTOR]); } /** diff --git a/gtk/gtkgesturestylus.c b/gtk/gtkgesturestylus.c index 2d49783baf..92d4a37226 100644 --- a/gtk/gtkgesturestylus.c +++ b/gtk/gtkgesturestylus.c @@ -322,6 +322,8 @@ gtk_gesture_stylus_get_backlog (GtkGestureStylus *gesture, guint n_coords = 0, i; double surf_x, surf_y; GtkNative *native; + GtkWidget *event_widget; + GtkWidget *controller_widget; g_return_val_if_fail (GTK_IS_GESTURE_STYLUS (gesture), FALSE); g_return_val_if_fail (backlog != NULL && n_elems != NULL, FALSE); @@ -338,28 +340,26 @@ gtk_gesture_stylus_get_backlog (GtkGestureStylus *gesture, gtk_native_get_surface_transform (native, &surf_x, &surf_y); backlog_array = g_array_new (FALSE, FALSE, sizeof (GdkTimeCoord)); + event_widget = gtk_get_event_widget (event); + controller_widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture)); for (i = 0; i < n_coords; i++) { - GdkTimeCoord *time_coord = &history[i]; + const GdkTimeCoord *time_coord = &history[i]; graphene_point_t p; - g_array_append_val (backlog_array, *time_coord); - time_coord = &g_array_index (backlog_array, GdkTimeCoord, backlog_array->len - 1); - - if (gtk_widget_compute_point (GTK_WIDGET (native), - gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture)), + if (gtk_widget_compute_point (event_widget, controller_widget, &GRAPHENE_POINT_INIT (time_coord->axes[GDK_AXIS_X] - surf_x, time_coord->axes[GDK_AXIS_Y] - surf_y), &p)) { - time_coord->axes[GDK_AXIS_X] = p.x; - time_coord->axes[GDK_AXIS_Y] = p.y; - } - else - { - g_array_set_size (backlog_array, backlog_array->len - 1); + GdkTimeCoord translated_coord = *time_coord; + + translated_coord.axes[GDK_AXIS_X] = p.x; + translated_coord.axes[GDK_AXIS_Y] = p.y; + + g_array_append_val (backlog_array, translated_coord); } - } + } *n_elems = backlog_array->len; *backlog = (GdkTimeCoord *) g_array_free (backlog_array, FALSE); diff --git a/gtk/gtkicontheme.c b/gtk/gtkicontheme.c index 9a469bdc66..a5bfdaf5a0 100644 --- a/gtk/gtkicontheme.c +++ b/gtk/gtkicontheme.c @@ -3133,7 +3133,7 @@ scan_directory (GtkIconTheme *self, static GHashTable * scan_resource_directory (GtkIconTheme *self, - char *full_dir, + const char *full_dir, GtkStringSet *set) { GHashTable *icons = NULL; diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c index 19b0386c05..1c8a31f231 100644 --- a/gtk/gtklabel.c +++ b/gtk/gtklabel.c @@ -407,168 +407,31 @@ static guint signals[LAST_SIGNAL] = { 0 }; static GQuark quark_mnemonics_visible_connected; -static void gtk_label_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); -static void gtk_label_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); -static void gtk_label_finalize (GObject *object); -static void gtk_label_dispose (GObject *object); -static void gtk_label_size_allocate (GtkWidget *widget, - int width, - int height, - int baseline); -static void gtk_label_state_flags_changed (GtkWidget *widget, - GtkStateFlags prev_state); -static void gtk_label_css_changed (GtkWidget *widget, - GtkCssStyleChange *change); -static void gtk_label_snapshot (GtkWidget *widget, - GtkSnapshot *snapshot); -static gboolean gtk_label_focus (GtkWidget *widget, - GtkDirectionType direction); - -static void gtk_label_unrealize (GtkWidget *widget); - -static void gtk_label_motion (GtkEventControllerMotion *controller, - double x, - double y, - gpointer data); -static void gtk_label_leave (GtkEventControllerMotion *controller, - gpointer data); - -static gboolean gtk_label_grab_focus (GtkWidget *widget); - -static gboolean gtk_label_query_tooltip (GtkWidget *widget, - int x, - int y, - gboolean keyboard_tip, - GtkTooltip *tooltip); - -static void gtk_label_set_text_internal (GtkLabel *self, - char *str); -static gboolean gtk_label_set_label_internal (GtkLabel *self, - const char *str); -static gboolean gtk_label_set_use_markup_internal (GtkLabel *self, - gboolean val); -static gboolean gtk_label_set_use_underline_internal (GtkLabel *self, - gboolean val); static void gtk_label_set_markup_internal (GtkLabel *self, - const char *str, - gboolean with_uline); + const char *str, + gboolean with_uline); static void gtk_label_recalculate (GtkLabel *self); -static void gtk_label_root (GtkWidget *widget); -static void gtk_label_unroot (GtkWidget *widget); -static void gtk_label_popup_menu (GtkWidget *widget, - const char *action_name, - GVariant *parameters); static void gtk_label_do_popup (GtkLabel *self, double x, double y); - static void gtk_label_ensure_select_info (GtkLabel *self); static void gtk_label_clear_select_info (GtkLabel *self); -static void gtk_label_update_cursor (GtkLabel *self); static void gtk_label_clear_layout (GtkLabel *self); static void gtk_label_ensure_layout (GtkLabel *self); static void gtk_label_select_region_index (GtkLabel *self, int anchor_index, int end_index); - static void gtk_label_update_active_link (GtkWidget *widget, double x, double y); - -static gboolean gtk_label_mnemonic_activate (GtkWidget *widget, - gboolean group_cycling); static void gtk_label_setup_mnemonic (GtkLabel *self); static void gtk_label_buildable_interface_init (GtkBuildableIface *iface); -static gboolean gtk_label_buildable_custom_tag_start (GtkBuildable *buildable, - GtkBuilder *builder, - GObject *child, - const char *tagname, - GtkBuildableParser *parser, - gpointer *data); - -static void gtk_label_buildable_custom_finished (GtkBuildable *buildable, - GtkBuilder *builder, - GObject *child, - const char *tagname, - gpointer user_data); - /* For selectable labels: */ static void gtk_label_move_cursor (GtkLabel *self, - GtkMovementStep step, - int count, - gboolean extend_selection); -static void gtk_label_copy_clipboard (GtkLabel *self); -static void gtk_label_select_all (GtkLabel *self); -static int gtk_label_move_forward_word (GtkLabel *self, - int start); -static int gtk_label_move_backward_word (GtkLabel *self, - int start); - -/* For links: */ -static void gtk_label_clear_links (GtkLabel *self); -static gboolean gtk_label_activate_link (GtkLabel *self, - const char *uri); -static void gtk_label_activate_current_link (GtkLabel *self); -static void emit_activate_link (GtkLabel *self, - GtkLabelLink *link); - -/* Event controller callbacks */ -static void gtk_label_click_gesture_pressed (GtkGestureClick *gesture, - int n_press, - double x, - double y, - GtkLabel *self); -static void gtk_label_click_gesture_released (GtkGestureClick *gesture, - int n_press, - double x, - double y, - GtkLabel *self); -static void gtk_label_drag_gesture_begin (GtkGestureDrag *gesture, - double start_x, - double start_y, - GtkLabel *self); -static void gtk_label_drag_gesture_update (GtkGestureDrag *gesture, - double offset_x, - double offset_y, - GtkLabel *self); - -/* Actions */ - -static void gtk_label_activate_clipboard_copy (GtkWidget *self, - const char *name, - GVariant *parameter); -static void gtk_label_activate_selection_select_all (GtkWidget *self, - const char *name, - GVariant *parameter); -static void gtk_label_activate_link_open (GtkWidget *self, - const char *name, - GVariant *parameter); -static void gtk_label_activate_link_copy (GtkWidget *self, - const char *name, - GVariant *parameter); -static void gtk_label_nop (GtkWidget *self, - const char *name, - GVariant *parameter); - -static void gtk_label_update_actions (GtkLabel *self); - -static GtkSizeRequestMode gtk_label_get_request_mode (GtkWidget *widget); -static void gtk_label_measure (GtkWidget *widget, - GtkOrientation orientation, - int for_size, - int *minimum, - int *natural, - int *minimum_baseline, - int *natural_baseline); - - + GtkMovementStep step, + int count, + gboolean extend_selection); static GtkBuildableIface *buildable_parent_iface = NULL; @@ -578,26 +441,1627 @@ G_DEFINE_TYPE_WITH_CODE (GtkLabel, gtk_label, GTK_TYPE_WIDGET, static void add_move_binding (GtkWidgetClass *widget_class, - guint keyval, - guint modmask, - GtkMovementStep step, - int count) + guint keyval, + guint modmask, + GtkMovementStep step, + int count) { g_return_if_fail ((modmask & GDK_SHIFT_MASK) == 0); - + gtk_widget_class_add_binding_signal (widget_class, keyval, modmask, - "move-cursor", + "move-cursor", "(iib)", step, count, FALSE); /* Selection-extending version */ gtk_widget_class_add_binding_signal (widget_class, keyval, modmask | GDK_SHIFT_MASK, - "move-cursor", + "move-cursor", "(iib)", step, count, TRUE); } static void +gtk_label_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GtkLabel *self = GTK_LABEL (object); + + switch (prop_id) + { + case PROP_LABEL: + gtk_label_set_label (self, g_value_get_string (value)); + break; + case PROP_ATTRIBUTES: + gtk_label_set_attributes (self, g_value_get_boxed (value)); + break; + case PROP_USE_MARKUP: + gtk_label_set_use_markup (self, g_value_get_boolean (value)); + break; + case PROP_USE_UNDERLINE: + gtk_label_set_use_underline (self, g_value_get_boolean (value)); + break; + case PROP_JUSTIFY: + gtk_label_set_justify (self, g_value_get_enum (value)); + break; + case PROP_WRAP: + gtk_label_set_wrap (self, g_value_get_boolean (value)); + break; + case PROP_WRAP_MODE: + gtk_label_set_wrap_mode (self, g_value_get_enum (value)); + break; + case PROP_SELECTABLE: + gtk_label_set_selectable (self, g_value_get_boolean (value)); + break; + case PROP_MNEMONIC_WIDGET: + gtk_label_set_mnemonic_widget (self, (GtkWidget*) g_value_get_object (value)); + break; + case PROP_ELLIPSIZE: + gtk_label_set_ellipsize (self, g_value_get_enum (value)); + break; + case PROP_WIDTH_CHARS: + gtk_label_set_width_chars (self, g_value_get_int (value)); + break; + case PROP_SINGLE_LINE_MODE: + gtk_label_set_single_line_mode (self, g_value_get_boolean (value)); + break; + case PROP_MAX_WIDTH_CHARS: + gtk_label_set_max_width_chars (self, g_value_get_int (value)); + break; + case PROP_LINES: + gtk_label_set_lines (self, g_value_get_int (value)); + break; + case PROP_XALIGN: + gtk_label_set_xalign (self, g_value_get_float (value)); + break; + case PROP_YALIGN: + gtk_label_set_yalign (self, g_value_get_float (value)); + break; + case PROP_EXTRA_MENU: + gtk_label_set_extra_menu (self, g_value_get_object (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gtk_label_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GtkLabel *self = GTK_LABEL (object); + + switch (prop_id) + { + case PROP_LABEL: + g_value_set_string (value, self->label); + break; + case PROP_ATTRIBUTES: + g_value_set_boxed (value, self->attrs); + break; + case PROP_USE_MARKUP: + g_value_set_boolean (value, self->use_markup); + break; + case PROP_USE_UNDERLINE: + g_value_set_boolean (value, self->use_underline); + break; + case PROP_JUSTIFY: + g_value_set_enum (value, self->jtype); + break; + case PROP_WRAP: + g_value_set_boolean (value, self->wrap); + break; + case PROP_WRAP_MODE: + g_value_set_enum (value, self->wrap_mode); + break; + case PROP_SELECTABLE: + g_value_set_boolean (value, gtk_label_get_selectable (self)); + break; + case PROP_MNEMONIC_KEYVAL: + g_value_set_uint (value, self->mnemonic_keyval); + break; + case PROP_MNEMONIC_WIDGET: + g_value_set_object (value, (GObject*) self->mnemonic_widget); + break; + case PROP_ELLIPSIZE: + g_value_set_enum (value, self->ellipsize); + break; + case PROP_WIDTH_CHARS: + g_value_set_int (value, gtk_label_get_width_chars (self)); + break; + case PROP_SINGLE_LINE_MODE: + g_value_set_boolean (value, gtk_label_get_single_line_mode (self)); + break; + case PROP_MAX_WIDTH_CHARS: + g_value_set_int (value, gtk_label_get_max_width_chars (self)); + break; + case PROP_LINES: + g_value_set_int (value, gtk_label_get_lines (self)); + break; + case PROP_XALIGN: + g_value_set_float (value, gtk_label_get_xalign (self)); + break; + case PROP_YALIGN: + g_value_set_float (value, gtk_label_get_yalign (self)); + break; + case PROP_EXTRA_MENU: + g_value_set_object (value, gtk_label_get_extra_menu (self)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gtk_label_init (GtkLabel *self) +{ + self->width_chars = -1; + self->max_width_chars = -1; + self->label = g_strdup (""); + self->lines = -1; + + self->xalign = 0.5; + self->yalign = 0.5; + + self->jtype = GTK_JUSTIFY_LEFT; + self->wrap = FALSE; + self->wrap_mode = PANGO_WRAP_WORD; + self->ellipsize = PANGO_ELLIPSIZE_NONE; + + self->use_underline = FALSE; + self->use_markup = FALSE; + + self->mnemonic_keyval = GDK_KEY_VoidSymbol; + self->layout = NULL; + self->text = g_strdup (""); + self->attrs = NULL; + + self->mnemonic_widget = NULL; + + self->mnemonics_visible = FALSE; +} + +static const GtkBuildableParser pango_parser = +{ + gtk_pango_attribute_start_element, +}; + +static gboolean +gtk_label_buildable_custom_tag_start (GtkBuildable *buildable, + GtkBuilder *builder, + GObject *child, + const char *tagname, + GtkBuildableParser *parser, + gpointer *data) +{ + if (buildable_parent_iface->custom_tag_start (buildable, builder, child, + tagname, parser, data)) + return TRUE; + + if (strcmp (tagname, "attributes") == 0) + { + GtkPangoAttributeParserData *parser_data; + + parser_data = g_slice_new0 (GtkPangoAttributeParserData); + parser_data->builder = g_object_ref (builder); + parser_data->object = (GObject *) g_object_ref (buildable); + *parser = pango_parser; + *data = parser_data; + return TRUE; + } + return FALSE; +} + +static void +gtk_label_buildable_custom_finished (GtkBuildable *buildable, + GtkBuilder *builder, + GObject *child, + const char *tagname, + gpointer user_data) +{ + GtkPangoAttributeParserData *data = user_data; + + buildable_parent_iface->custom_finished (buildable, builder, child, + tagname, user_data); + + if (strcmp (tagname, "attributes") == 0) + { + if (data->attrs) + { + gtk_label_set_attributes (GTK_LABEL (buildable), data->attrs); + pango_attr_list_unref (data->attrs); + } + + g_object_unref (data->object); + g_object_unref (data->builder); + g_slice_free (GtkPangoAttributeParserData, data); + } +} + +static void +gtk_label_buildable_interface_init (GtkBuildableIface *iface) +{ + buildable_parent_iface = g_type_interface_peek_parent (iface); + + iface->custom_tag_start = gtk_label_buildable_custom_tag_start; + iface->custom_finished = gtk_label_buildable_custom_finished; +} + +static void +update_link_state (GtkLabel *self) +{ + GtkStateFlags state; + guint i; + + if (!self->select_info) + return; + + for (i = 0; i < self->select_info->n_links; i++) + { + const GtkLabelLink *link = &self->select_info->links[i]; + + state = gtk_widget_get_state_flags (GTK_WIDGET (self)); + if (link->visited) + state |= GTK_STATE_FLAG_VISITED; + else + state |= GTK_STATE_FLAG_LINK; + if (link == self->select_info->active_link) + { + if (self->select_info->link_clicked) + state |= GTK_STATE_FLAG_ACTIVE; + else + state |= GTK_STATE_FLAG_PRELIGHT; + } + gtk_css_node_set_state (link->cssnode, state); + } +} + +static void +gtk_label_update_cursor (GtkLabel *self) +{ + GtkWidget *widget = GTK_WIDGET (self); + + if (!self->select_info) + return; + + if (gtk_widget_is_sensitive (widget)) + { + if (self->select_info->active_link) + gtk_widget_set_cursor_from_name (widget, "pointer"); + else if (self->select_info->selectable) + gtk_widget_set_cursor_from_name (widget, "text"); + else + gtk_widget_set_cursor (widget, NULL); + } + else + gtk_widget_set_cursor (widget, NULL); +} + +static void +gtk_label_state_flags_changed (GtkWidget *widget, + GtkStateFlags prev_state) +{ + GtkLabel *self = GTK_LABEL (widget); + + if (self->select_info) + { + if (!gtk_widget_is_sensitive (widget)) + gtk_label_select_region (self, 0, 0); + + gtk_label_update_cursor (self); + update_link_state (self); + } + + if (GTK_WIDGET_CLASS (gtk_label_parent_class)->state_flags_changed) + GTK_WIDGET_CLASS (gtk_label_parent_class)->state_flags_changed (widget, prev_state); +} + +static void +gtk_label_update_layout_attributes (GtkLabel *self, + PangoAttrList *style_attrs) +{ + GtkWidget *widget = GTK_WIDGET (self); + GtkCssStyle *style; + PangoAttrList *attrs; + + if (self->layout == NULL) + { + pango_attr_list_unref (style_attrs); + return; + } + + if (self->select_info && self->select_info->links) + { + guint i; + + attrs = pango_attr_list_new (); + + for (i = 0; i < self->select_info->n_links; i++) + { + const GtkLabelLink *link = &self->select_info->links[i]; + const GdkRGBA *link_color; + PangoAttrList *link_attrs; + PangoAttribute *attr; + + style = gtk_css_node_get_style (link->cssnode); + link_attrs = gtk_css_style_get_pango_attributes (style); + if (link_attrs) + { + GSList *attributes = pango_attr_list_get_attributes (link_attrs); + GSList *l; + for (l = attributes; l; l = l->next) + { + attr = l->data; + + attr->start_index = link->start; + attr->end_index = link->end; + pango_attr_list_insert (attrs, attr); + } + g_slist_free (attributes); + } + + link_color = gtk_css_color_value_get_rgba (style->core->color); + attr = pango_attr_foreground_new (link_color->red * 65535, + link_color->green * 65535, + link_color->blue * 65535); + attr->start_index = link->start; + attr->end_index = link->end; + pango_attr_list_insert (attrs, attr); + + pango_attr_list_unref (link_attrs); + } + } + else + attrs = NULL; + + style = gtk_css_node_get_style (gtk_widget_get_css_node (widget)); + if (!style_attrs) + style_attrs = gtk_css_style_get_pango_attributes (style); + + if (style_attrs) + { + attrs = _gtk_pango_attr_list_merge (attrs, style_attrs); + pango_attr_list_unref (style_attrs); + } + + attrs = _gtk_pango_attr_list_merge (attrs, self->markup_attrs); + attrs = _gtk_pango_attr_list_merge (attrs, self->attrs); + + pango_layout_set_attributes (self->layout, attrs); + + pango_attr_list_unref (attrs); +} + +static void +gtk_label_css_changed (GtkWidget *widget, + GtkCssStyleChange *change) +{ + GtkLabel *self = GTK_LABEL (widget); + gboolean attrs_affected; + PangoAttrList *new_attrs = NULL; + + GTK_WIDGET_CLASS (gtk_label_parent_class)->css_changed (widget, change); + + if (gtk_css_style_change_affects (change, GTK_CSS_AFFECTS_TEXT_ATTRS)) + { + new_attrs = gtk_css_style_get_pango_attributes (gtk_css_style_change_get_new_style (change)); + attrs_affected = (self->layout && pango_layout_get_attributes (self->layout)) || + new_attrs; + } + else + attrs_affected = FALSE; + + if (change == NULL || attrs_affected || (self->select_info && self->select_info->links)) + { + gtk_label_update_layout_attributes (self, new_attrs); + + if (attrs_affected) + gtk_widget_queue_draw (widget); + } +} + +static PangoDirection +get_cursor_direction (GtkLabel *self) +{ + GSList *l; + + g_assert (self->select_info); + + gtk_label_ensure_layout (self); + + for (l = pango_layout_get_lines_readonly (self->layout); l; l = l->next) + { + PangoLayoutLine *line = l->data; + + /* If self->select_info->selection_end is at the very end of + * the line, we don't know if the cursor is on this line or + * the next without looking ahead at the next line. (End + * of paragraph is different from line break.) But it's + * definitely in this paragraph, which is good enough + * to figure out the resolved direction. + */ + if (line->start_index + line->length >= self->select_info->selection_end) + return line->resolved_dir; + } + + return PANGO_DIRECTION_LTR; +} + +static int +_gtk_label_get_link_at (GtkLabel *self, + int pos) +{ + if (self->select_info) + { + guint i; + + for (i = 0; i < self->select_info->n_links; i++) + { + const GtkLabelLink *link = &self->select_info->links[i]; + + if (link->start <= pos && pos < link->end) + return i; + } + } + + return -1; +} + +static GtkLabelLink * +gtk_label_get_focus_link (GtkLabel *self, + int *out_index) +{ + GtkLabelSelectionInfo *info = self->select_info; + int link_index; + + if (!info || + info->selection_anchor != info->selection_end) + goto nope; + + link_index = _gtk_label_get_link_at (self, info->selection_anchor); + + if (link_index != -1) + { + if (out_index) + *out_index = link_index; + + return &info->links[link_index]; + } + +nope: + if (out_index) + *out_index = -1; + return NULL; +} + +/** + * gtk_label_get_measuring_layout: + * @self: the label + * @existing_layout: %NULL or an existing layout already in use. + * @width: the width to measure with in pango units, or -1 for infinite + * + * Gets a layout that can be used for measuring sizes. The returned + * layout will be identical to the label’s layout except for the + * layout’s width, which will be set to @width. Do not modify the returned + * layout. + * + * Returns: a new reference to a pango layout + **/ +static PangoLayout * +gtk_label_get_measuring_layout (GtkLabel *self, + PangoLayout *existing_layout, + int width) +{ + PangoLayout *copy; + + if (existing_layout != NULL) + { + if (existing_layout != self->layout) + { + pango_layout_set_width (existing_layout, width); + return existing_layout; + } + + g_object_unref (existing_layout); + } + + gtk_label_ensure_layout (self); + + if (pango_layout_get_width (self->layout) == width) + { + g_object_ref (self->layout); + return self->layout; + } + + /* We can use the label's own layout if we're not allocated a size yet, + * because we don't need it to be properly setup at that point. + * This way we can make use of caching upon the label's creation. + */ + if (gtk_widget_get_width (GTK_WIDGET (self)) <= 1) + { + g_object_ref (self->layout); + pango_layout_set_width (self->layout, width); + return self->layout; + } + + /* oftentimes we want to measure a width that is far wider than the current width, + * even though the layout would not change if we made it wider. In that case, we + * can just return the current layout, because for measuring purposes, it will be + * identical. + */ + if (!pango_layout_is_wrapped (self->layout) && + !pango_layout_is_ellipsized (self->layout)) + { + PangoRectangle rect; + + if (width == -1) + return g_object_ref (self->layout); + + pango_layout_get_extents (self->layout, NULL, &rect); + if (rect.width <= width) + return g_object_ref (self->layout); + } + + copy = pango_layout_copy (self->layout); + pango_layout_set_width (copy, width); + return copy; +} + +static void +get_height_for_width (GtkLabel *self, + int width, + int *minimum_height, + int *natural_height, + int *minimum_baseline, + int *natural_baseline) +{ + PangoLayout *layout; + int text_height, baseline; + + layout = gtk_label_get_measuring_layout (self, NULL, width * PANGO_SCALE); + + pango_layout_get_pixel_size (layout, NULL, &text_height); + + *minimum_height = text_height; + *natural_height = text_height; + + baseline = pango_layout_get_baseline (layout) / PANGO_SCALE; + *minimum_baseline = baseline; + *natural_baseline = baseline; + + g_object_unref (layout); +} + +static int +get_char_pixels (GtkWidget *self, + PangoLayout *layout) +{ + PangoContext *context; + PangoFontMetrics *metrics; + int char_width, digit_width; + + context = pango_layout_get_context (layout); + metrics = pango_context_get_metrics (context, + pango_context_get_font_description (context), + pango_context_get_language (context)); + char_width = pango_font_metrics_get_approximate_char_width (metrics); + digit_width = pango_font_metrics_get_approximate_digit_width (metrics); + pango_font_metrics_unref (metrics); + + return MAX (char_width, digit_width);; +} + +static void +gtk_label_get_preferred_layout_size (GtkLabel *self, + PangoRectangle *smallest, + PangoRectangle *widest, + int *smallest_baseline, + int *widest_baseline) +{ + PangoLayout *layout; + int char_pixels; + + /* "width-chars" Hard-coded minimum width: + * - minimum size should be MAX (width-chars, strlen ("...")); + * - natural size should be MAX (width-chars, strlen (self->text)); + * + * "max-width-chars" User specified maximum size requisition + * - minimum size should be MAX (width-chars, 0) + * - natural size should be MIN (max-width-chars, strlen (self->text)) + * + * For ellipsizing labels; if max-width-chars is specified: either it is used as + * a minimum size or the label text as a minimum size (natural size still overflows). + * + * For wrapping labels; A reasonable minimum size is useful to naturally layout + * interfaces automatically. In this case if no "width-chars" is specified, the minimum + * width will default to the wrap guess that gtk_label_ensure_layout() does. + */ + + /* Start off with the pixel extents of an as-wide-as-possible layout */ + layout = gtk_label_get_measuring_layout (self, NULL, -1); + + if (self->width_chars > -1 || self->max_width_chars > -1) + char_pixels = get_char_pixels (GTK_WIDGET (self), layout); + else + char_pixels = 0; + + pango_layout_get_extents (layout, NULL, widest); + widest->width = MAX (widest->width, char_pixels * self->width_chars); + widest->x = widest->y = 0; + *widest_baseline = pango_layout_get_baseline (layout) / PANGO_SCALE; + + if (self->ellipsize || self->wrap) + { + /* a layout with width 0 will be as small as humanly possible */ + layout = gtk_label_get_measuring_layout (self, + layout, + self->width_chars > -1 ? char_pixels * self->width_chars + : 0); + + pango_layout_get_extents (layout, NULL, smallest); + smallest->width = MAX (smallest->width, char_pixels * self->width_chars); + smallest->x = smallest->y = 0; + + *smallest_baseline = pango_layout_get_baseline (layout) / PANGO_SCALE; + + if (self->max_width_chars > -1 && widest->width > char_pixels * self->max_width_chars) + { + layout = gtk_label_get_measuring_layout (self, + layout, + MAX (smallest->width, char_pixels * self->max_width_chars)); + pango_layout_get_extents (layout, NULL, widest); + widest->width = MAX (widest->width, char_pixels * self->width_chars); + widest->x = widest->y = 0; + + *widest_baseline = pango_layout_get_baseline (layout) / PANGO_SCALE; + } + + if (widest->width < smallest->width) + { + *smallest = *widest; + *smallest_baseline = *widest_baseline; + } + } + else + { + *smallest = *widest; + *smallest_baseline = *widest_baseline; + } + + g_object_unref (layout); +} + +static void +gtk_label_get_preferred_size (GtkWidget *widget, + GtkOrientation orientation, + int *minimum_size, + int *natural_size, + int *minimum_baseline, + int *natural_baseline) +{ + GtkLabel *self = GTK_LABEL (widget); + PangoRectangle widest_rect; + PangoRectangle smallest_rect; + int smallest_baseline; + int widest_baseline; + + gtk_label_get_preferred_layout_size (self, + &smallest_rect, &widest_rect, + &smallest_baseline, &widest_baseline); + + widest_rect.width = PANGO_PIXELS_CEIL (widest_rect.width); + widest_rect.height = PANGO_PIXELS_CEIL (widest_rect.height); + + smallest_rect.width = PANGO_PIXELS_CEIL (smallest_rect.width); + smallest_rect.height = PANGO_PIXELS_CEIL (smallest_rect.height); + + if (orientation == GTK_ORIENTATION_HORIZONTAL) + { + /* Normal desired width */ + *minimum_size = smallest_rect.width; + *natural_size = widest_rect.width; + + if (minimum_baseline) + *minimum_baseline = -1; + + if (natural_baseline) + *natural_baseline = -1; + } + else /* GTK_ORIENTATION_VERTICAL */ + { + if (smallest_rect.height < widest_rect.height) + { + *minimum_size = smallest_rect.height; + *natural_size = widest_rect.height; + if (minimum_baseline) + *minimum_baseline = smallest_baseline; + if (natural_baseline) + *natural_baseline = widest_baseline; + } + else + { + *minimum_size = widest_rect.height; + *natural_size = smallest_rect.height; + if (minimum_baseline) + *minimum_baseline = widest_baseline; + if (natural_baseline) + *natural_baseline = smallest_baseline; + } + } +} + + +static void +gtk_label_measure (GtkWidget *widget, + GtkOrientation orientation, + int for_size, + int *minimum, + int *natural, + int *minimum_baseline, + int *natural_baseline) +{ + GtkLabel *self = GTK_LABEL (widget); + + if (orientation == GTK_ORIENTATION_VERTICAL && for_size != -1 && self->wrap) + { + gtk_label_clear_layout (self); + + get_height_for_width (self, for_size, minimum, natural, minimum_baseline, natural_baseline); + } + else + gtk_label_get_preferred_size (widget, orientation, minimum, natural, minimum_baseline, natural_baseline); +} + +static void +get_layout_location (GtkLabel *self, + int *xp, + int *yp) +{ + GtkWidget *widget = GTK_WIDGET (self); + int layout_width, layout_height, x, y; + float xalign, yalign; + PangoRectangle logical; + int baseline, layout_baseline, baseline_offset; + int widget_width, widget_height; + + xalign = self->xalign; + yalign = self->yalign; + + if (_gtk_widget_get_direction (widget) != GTK_TEXT_DIR_LTR) + xalign = 1.0 - xalign; + + pango_layout_get_pixel_extents (self->layout, NULL, &logical); + + layout_width = logical.width; + layout_height = logical.height; + + widget_width = gtk_widget_get_width (widget); + widget_height = gtk_widget_get_height (widget); + + baseline = gtk_widget_get_allocated_baseline (widget); + + x = floor ((xalign * (widget_width - layout_width)) - logical.x); + + baseline_offset = 0; + if (baseline != -1) + { + layout_baseline = pango_layout_get_baseline (self->layout) / PANGO_SCALE; + baseline_offset = baseline - layout_baseline; + yalign = 0.0; /* Can't support yalign while baseline aligning */ + } + + y = floor ((widget_height - layout_height) * yalign) + baseline_offset; + + if (xp) + *xp = x; + + if (yp) + *yp = y; +} + +static void +gtk_label_size_allocate (GtkWidget *widget, + int width, + int height, + int baseline) +{ + GtkLabel *self = GTK_LABEL (widget); + + if (self->layout) + { + if (self->ellipsize || self->wrap) + pango_layout_set_width (self->layout, width * PANGO_SCALE); + else + pango_layout_set_width (self->layout, -1); + } + + if (self->popup_menu) + gtk_popover_present (GTK_POPOVER (self->popup_menu)); +} + + + +#define GRAPHENE_RECT_FROM_RECT(_r) (GRAPHENE_RECT_INIT ((_r)->x, (_r)->y, (_r)->width, (_r)->height)) + +static void +gtk_label_snapshot (GtkWidget *widget, + GtkSnapshot *snapshot) +{ + GtkLabel *self = GTK_LABEL (widget); + GtkLabelSelectionInfo *info; + GtkStyleContext *context; + int lx, ly; + int width, height; + + if (!self->text || (*self->text == '\0')) + return; + + gtk_label_ensure_layout (self); + + context = _gtk_widget_get_style_context (widget); + get_layout_location (self, &lx, &ly); + + gtk_snapshot_render_layout (snapshot, context, lx, ly, self->layout); + + info = self->select_info; + if (!info) + return; + + width = gtk_widget_get_width (widget); + height = gtk_widget_get_height (widget); + + if (info->selection_anchor != info->selection_end) + { + int range[2]; + cairo_region_t *range_clip; + cairo_rectangle_int_t clip_rect; + int i; + + range[0] = MIN (info->selection_anchor, info->selection_end); + range[1] = MAX (info->selection_anchor, info->selection_end); + + gtk_style_context_save_to_node (context, info->selection_node); + + range_clip = gdk_pango_layout_get_clip_region (self->layout, lx, ly, range, 1); + for (i = 0; i < cairo_region_num_rectangles (range_clip); i++) + { + cairo_region_get_rectangle (range_clip, i, &clip_rect); + + gtk_snapshot_push_clip (snapshot, &GRAPHENE_RECT_FROM_RECT (&clip_rect)); + gtk_snapshot_render_background (snapshot, context, 0, 0, width, height); + gtk_snapshot_render_layout (snapshot, context, lx, ly, self->layout); + gtk_snapshot_pop (snapshot); + } + + cairo_region_destroy (range_clip); + + gtk_style_context_restore (context); + } + else + { + GtkLabelLink *focus_link; + GtkLabelLink *active_link; + int range[2]; + cairo_region_t *range_clip; + cairo_rectangle_int_t clip_rect; + int i; + GdkRectangle rect; + + if (info->selectable && + gtk_widget_has_focus (widget) && + gtk_widget_is_drawable (widget)) + { + PangoDirection cursor_direction; + + cursor_direction = get_cursor_direction (self); + gtk_snapshot_render_insertion_cursor (snapshot, context, + lx, ly, + self->layout, self->select_info->selection_end, + cursor_direction); + } + + focus_link = gtk_label_get_focus_link (self, NULL); + active_link = info->active_link; + + if (active_link) + { + range[0] = active_link->start; + range[1] = active_link->end; + + gtk_style_context_save_to_node (context, active_link->cssnode); + + range_clip = gdk_pango_layout_get_clip_region (self->layout, lx, ly, range, 1); + for (i = 0; i < cairo_region_num_rectangles (range_clip); i++) + { + cairo_region_get_rectangle (range_clip, i, &clip_rect); + + gtk_snapshot_push_clip (snapshot, &GRAPHENE_RECT_FROM_RECT (&clip_rect)); + gtk_snapshot_render_background (snapshot, context, 0, 0, width, height); + gtk_snapshot_render_layout (snapshot, context, lx, ly, self->layout); + gtk_snapshot_pop (snapshot); + } + + cairo_region_destroy (range_clip); + + gtk_style_context_restore (context); + } + + if (focus_link && gtk_widget_has_visible_focus (widget)) + { + range[0] = focus_link->start; + range[1] = focus_link->end; + + gtk_style_context_save_to_node (context, focus_link->cssnode); + + range_clip = gdk_pango_layout_get_clip_region (self->layout, lx, ly, range, 1); + cairo_region_get_extents (range_clip, &rect); + + gtk_snapshot_render_focus (snapshot, context, rect.x, rect.y, rect.width, rect.height); + + cairo_region_destroy (range_clip); + + gtk_style_context_restore (context); + } + } +} + +static GtkSizeRequestMode +gtk_label_get_request_mode (GtkWidget *widget) +{ + GtkLabel *self = GTK_LABEL (widget); + + if (self->wrap) + return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH; + + return GTK_SIZE_REQUEST_CONSTANT_SIZE; +} + +static void +gtk_label_dispose (GObject *object) +{ + GtkLabel *self = GTK_LABEL (object); + + gtk_label_set_mnemonic_widget (self, NULL); + + G_OBJECT_CLASS (gtk_label_parent_class)->dispose (object); +} + +static void +gtk_label_clear_links (GtkLabel *self) +{ + guint i; + + if (!self->select_info) + return; + + for (i = 0; i < self->select_info->n_links; i++) + { + const GtkLabelLink *link = &self->select_info->links[i]; + gtk_css_node_set_parent (link->cssnode, NULL); + g_free (link->uri); + g_free (link->title); + } + g_free (self->select_info->links); + self->select_info->links = NULL; + self->select_info->n_links = 0; + self->select_info->active_link = NULL; + gtk_widget_remove_css_class (GTK_WIDGET (self), "link"); +} + +static void +gtk_label_finalize (GObject *object) +{ + GtkLabel *self = GTK_LABEL (object); + + g_free (self->label); + g_free (self->text); + + g_clear_object (&self->layout); + g_clear_pointer (&self->attrs, pango_attr_list_unref); + g_clear_pointer (&self->markup_attrs, pango_attr_list_unref); + + if (self->select_info) + g_object_unref (self->select_info->provider); + + gtk_label_clear_links (self); + g_free (self->select_info); + + g_clear_pointer (&self->popup_menu, gtk_widget_unparent); + g_clear_object (&self->extra_menu); + + G_OBJECT_CLASS (gtk_label_parent_class)->finalize (object); +} + +static void +gtk_label_unrealize (GtkWidget *widget) +{ + GtkLabel *self = GTK_LABEL (widget); + + if (self->select_info && + self->select_info->provider) + { + GdkClipboard *clipboard = gtk_widget_get_primary_clipboard (widget); + + if (gdk_clipboard_get_content (clipboard) == self->select_info->provider) + gdk_clipboard_set_content (clipboard, NULL); + } + + GTK_WIDGET_CLASS (gtk_label_parent_class)->unrealize (widget); +} + +static gboolean +range_is_in_ellipsis_full (GtkLabel *self, + int range_start, + int range_end, + int *ellipsis_start, + int *ellipsis_end) +{ + PangoLayoutIter *iter; + gboolean in_ellipsis; + + if (!self->ellipsize) + return FALSE; + + gtk_label_ensure_layout (self); + + if (!pango_layout_is_ellipsized (self->layout)) + return FALSE; + + iter = pango_layout_get_iter (self->layout); + + in_ellipsis = FALSE; + + do { + PangoLayoutRun *run; + + run = pango_layout_iter_get_run_readonly (iter); + if (run) + { + PangoItem *item; + + item = ((PangoGlyphItem*)run)->item; + + if (item->offset <= range_start && range_end <= item->offset + item->length) + { + if (item->analysis.flags & PANGO_ANALYSIS_FLAG_IS_ELLIPSIS) + { + if (ellipsis_start) + *ellipsis_start = item->offset; + if (ellipsis_end) + *ellipsis_end = item->offset + item->length; + in_ellipsis = TRUE; + } + break; + } + else if (item->offset + item->length >= range_end) + break; + } + } while (pango_layout_iter_next_run (iter)); + + pango_layout_iter_free (iter); + + return in_ellipsis; +} + +static gboolean +range_is_in_ellipsis (GtkLabel *self, + int range_start, + int range_end) +{ + return range_is_in_ellipsis_full (self, range_start, range_end, NULL, NULL); +} + +static gboolean +gtk_label_grab_focus (GtkWidget *widget) +{ + GtkLabel *self = GTK_LABEL (widget); + gboolean select_on_focus; + GtkWidget *prev_focus; + + if (self->select_info == NULL) + return FALSE; + + prev_focus = gtk_root_get_focus (gtk_widget_get_root (widget)); + + if (!GTK_WIDGET_CLASS (gtk_label_parent_class)->grab_focus (widget)) + return FALSE; + + if (self->select_info->selectable) + { + g_object_get (gtk_widget_get_settings (widget), + "gtk-label-select-on-focus", + &select_on_focus, + NULL); + + if (select_on_focus && !self->in_click && + !(prev_focus && gtk_widget_is_ancestor (prev_focus, widget))) + gtk_label_select_region (self, 0, -1); + } + else + { + if (self->select_info->links && !self->in_click && + !(prev_focus && gtk_widget_is_ancestor (prev_focus, widget))) + { + guint i; + + for (i = 0; i < self->select_info->n_links; i++) + { + const GtkLabelLink *link = &self->select_info->links[i]; + + if (!range_is_in_ellipsis (self, link->start, link->end)) + { + self->select_info->selection_anchor = link->start; + self->select_info->selection_end = link->start; + break; + } + } + } + } + + return TRUE; +} + +static gboolean +get_layout_index (GtkLabel *self, + int x, + int y, + int *index) +{ + int trailing = 0; + const char *cluster; + const char *cluster_end; + gboolean inside; + int lx, ly; + + *index = 0; + + gtk_label_ensure_layout (self); + get_layout_location (self, &lx, &ly); + + /* Translate x/y to layout position */ + x -= lx; + y -= ly; + + x *= PANGO_SCALE; + y *= PANGO_SCALE; + + inside = pango_layout_xy_to_index (self->layout, + x, y, + index, &trailing); + + cluster = self->text + *index; + cluster_end = cluster; + while (trailing) + { + cluster_end = g_utf8_next_char (cluster_end); + --trailing; + } + + *index += (cluster_end - cluster); + + return inside; +} + +static gboolean +gtk_label_query_tooltip (GtkWidget *widget, + int x, + int y, + gboolean keyboard_tip, + GtkTooltip *tooltip) +{ + GtkLabel *self = GTK_LABEL (widget); + GtkLabelSelectionInfo *info = self->select_info; + int index = -1; + + if (info && info->links) + { + if (keyboard_tip) + { + if (info->selection_anchor == info->selection_end) + index = info->selection_anchor; + } + else + { + if (!get_layout_index (self, x, y, &index)) + index = -1; + } + + if (index != -1) + { + const int link_index = _gtk_label_get_link_at (self, index); + + if (link_index != -1) + { + const GtkLabelLink *link = &info->links[link_index]; + + if (link->title) + { + gtk_tooltip_set_markup (tooltip, link->title); + } + } + } + } + + return GTK_WIDGET_CLASS (gtk_label_parent_class)->query_tooltip (widget, + x, y, + keyboard_tip, + tooltip); +} + +static gboolean +gtk_label_focus (GtkWidget *widget, + GtkDirectionType direction) +{ + GtkLabel *self = GTK_LABEL (widget); + GtkLabelSelectionInfo *info = self->select_info; + GtkLabelLink *focus_link; + + if (!gtk_widget_is_focus (widget)) + { + gtk_widget_grab_focus (widget); + if (info) + { + focus_link = gtk_label_get_focus_link (self, NULL); + if (focus_link && direction == GTK_DIR_TAB_BACKWARD) + { + int i; + for (i = info->n_links - 1; i >= 0; i--) + { + focus_link = &info->links[i]; + if (!range_is_in_ellipsis (self, focus_link->start, focus_link->end)) + { + info->selection_anchor = focus_link->start; + info->selection_end = focus_link->start; + } + } + } + + return TRUE; + } + + return FALSE; + } + + if (!info) + return FALSE; + + if (info->selectable) + { + int index; + + if (info->selection_anchor != info->selection_end) + goto out; + + index = info->selection_anchor; + + if (direction == GTK_DIR_TAB_FORWARD) + { + guint i; + for (i = 0; i < info->n_links; i++) + { + const GtkLabelLink *link = &info->links[i]; + + if (link->start > index) + { + if (!range_is_in_ellipsis (self, link->start, link->end)) + { + gtk_label_select_region_index (self, link->start, link->start); + return TRUE; + } + } + } + } + else if (direction == GTK_DIR_TAB_BACKWARD) + { + int i; + for (i = info->n_links - 1; i >= 0; i--) + { + GtkLabelLink *link = &info->links[i]; + + if (link->end < index) + { + if (!range_is_in_ellipsis (self, link->start, link->end)) + { + gtk_label_select_region_index (self, link->start, link->start); + return TRUE; + } + } + } + } + + goto out; + } + else + { + int focus_link_index; + int new_index = -1; + int i; + + if (info->n_links == 0) + goto out; + + focus_link = gtk_label_get_focus_link (self, &focus_link_index); + + if (!focus_link) + goto out; + + switch (direction) + { + case GTK_DIR_TAB_FORWARD: + if (focus_link) + new_index = (focus_link_index + 1) % info->n_links; + else + new_index = 0; + + for (i = new_index; i < info->n_links; i++) + { + const GtkLabelLink *link = &info->links[i]; + if (!range_is_in_ellipsis (self, link->start, link->end)) + break; + } + break; + + case GTK_DIR_TAB_BACKWARD: + if (focus_link) + new_index = focus_link_index == 0 ? info->n_links - 1 : focus_link_index - 1; + else + new_index = info->n_links - 1; + + for (i = new_index; i >= 0; i--) + { + const GtkLabelLink *link = &info->links[i]; + if (!range_is_in_ellipsis (self, link->start, link->end)) + break; + } + break; + + default: + case GTK_DIR_UP: + case GTK_DIR_DOWN: + case GTK_DIR_LEFT: + case GTK_DIR_RIGHT: + goto out; + } + + if (new_index != -1) + { + focus_link = &info->links[new_index]; + info->selection_anchor = focus_link->start; + info->selection_end = focus_link->start; + gtk_widget_queue_draw (widget); + + return TRUE; + } + } + +out: + + return FALSE; +} + +static void +emit_activate_link (GtkLabel *self, + GtkLabelLink *link) +{ + gboolean handled; + + g_signal_emit (self, signals[ACTIVATE_LINK], 0, link->uri, &handled); + + /* signal handler might have invalidated the layout */ + if (!self->layout) + return; + + if (handled && !link->visited && + self->select_info && self->select_info->links) + { + link->visited = TRUE; + update_link_state (self); + } +} + +static void +gtk_label_activate_link_open (GtkWidget *widget, + const char *name, + GVariant *parameter) +{ + GtkLabel *self = GTK_LABEL (widget); + GtkLabelLink *link = self->select_info->context_link; + + if (link) + emit_activate_link (self, link); +} + +static void +gtk_label_activate_link_copy (GtkWidget *widget, + const char *name, + GVariant *parameter) +{ + GtkLabel *self = GTK_LABEL (widget); + GtkLabelLink *link = self->select_info->context_link; + + if (link) + { + GdkClipboard *clipboard; + + clipboard = gtk_widget_get_clipboard (widget); + gdk_clipboard_set_text (clipboard, link->uri); + } + else + g_print ("no link ?!\n"); +} + +static void +gtk_label_activate_clipboard_copy (GtkWidget *widget, + const char *name, + GVariant *parameter) +{ + g_signal_emit_by_name (widget, "copy-clipboard"); +} + +static void +gtk_label_select_all (GtkLabel *self) +{ + gtk_label_select_region_index (self, 0, strlen (self->text)); +} + +static void +gtk_label_activate_selection_select_all (GtkWidget *widget, + const char *name, + GVariant *parameter) +{ + gtk_label_select_all (GTK_LABEL (widget)); +} + +static void +gtk_label_nop (GtkWidget *widget, + const char *name, + GVariant *parameter) +{ +} + +static gboolean +gtk_label_mnemonic_activate (GtkWidget *widget, + gboolean group_cycling) +{ + GtkLabel *self = GTK_LABEL (widget); + GtkWidget *parent; + + if (self->mnemonic_widget) + return gtk_widget_mnemonic_activate (self->mnemonic_widget, group_cycling); + + /* Try to find the widget to activate by traversing the + * widget's ancestry. + */ + parent = gtk_widget_get_parent (widget); + + if (GTK_IS_NOTEBOOK (parent)) + return FALSE; + + while (parent) + { + if (gtk_widget_get_can_focus (parent) || + (!group_cycling && gtk_widget_can_activate (parent)) || + GTK_IS_NOTEBOOK (gtk_widget_get_parent (parent))) + return gtk_widget_mnemonic_activate (parent, group_cycling); + parent = gtk_widget_get_parent (parent); + } + + /* barf if there was nothing to activate */ + g_warning ("Couldn't find a target for a mnemonic activation."); + gtk_widget_error_bell (widget); + + return FALSE; +} + +static void +gtk_label_popup_menu (GtkWidget *widget, + const char *action_name, + GVariant *parameters) +{ + GtkLabel *self = GTK_LABEL (widget); + + gtk_label_do_popup (self, -1, -1); +} + +static void +gtk_label_root (GtkWidget *widget) +{ + GtkLabel *self = GTK_LABEL (widget); + + GTK_WIDGET_CLASS (gtk_label_parent_class)->root (widget); + + gtk_label_setup_mnemonic (self); + + /* The PangoContext is replaced when the display changes, so clear the layouts */ + gtk_label_clear_layout (GTK_LABEL (widget)); +} + +static void +gtk_label_unroot (GtkWidget *widget) +{ + GtkLabel *self = GTK_LABEL (widget); + + gtk_label_setup_mnemonic (self); + + GTK_WIDGET_CLASS (gtk_label_parent_class)->unroot (widget); +} + +static gboolean +gtk_label_activate_link (GtkLabel *self, + const char *uri) +{ + GtkWidget *widget = GTK_WIDGET (self); + GtkWidget *toplevel = GTK_WIDGET (gtk_widget_get_root (widget)); + + if (!GTK_IS_WINDOW (toplevel)) + return FALSE; + + gtk_show_uri (GTK_WINDOW (toplevel), uri, GDK_CURRENT_TIME); + + return TRUE; +} + +static void +gtk_label_activate_current_link (GtkLabel *self) +{ + GtkLabelLink *link; + GtkWidget *widget = GTK_WIDGET (self); + + link = gtk_label_get_focus_link (self, NULL); + + if (link) + emit_activate_link (self, link); + else + gtk_widget_activate_default (widget); +} + +static void +gtk_label_copy_clipboard (GtkLabel *self) +{ + if (self->text && self->select_info) + { + int start, end; + int len; + GdkClipboard *clipboard; + + start = MIN (self->select_info->selection_anchor, + self->select_info->selection_end); + end = MAX (self->select_info->selection_anchor, + self->select_info->selection_end); + + len = strlen (self->text); + + if (end > len) + end = len; + + if (start > len) + start = len; + + clipboard = gtk_widget_get_clipboard (GTK_WIDGET (self)); + + if (start != end) + { + char *str = g_strndup (self->text + start, end - start); + gdk_clipboard_set_text (clipboard, str); + g_free (str); + } + else + { + GtkLabelLink *link; + + link = gtk_label_get_focus_link (self, NULL); + if (link) + gdk_clipboard_set_text (clipboard, link->uri); + } + } +} + +static void gtk_label_class_init (GtkLabelClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS (class); @@ -651,17 +2115,17 @@ gtk_label_class_init (GtkLabelClass *class) * - Ctrl-arrow key combinations move by words/paragraphs * - Home/End keys move to the ends of the buffer */ - signals[MOVE_CURSOR] = + signals[MOVE_CURSOR] = g_signal_new (I_("move-cursor"), - G_OBJECT_CLASS_TYPE (gobject_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (GtkLabelClass, move_cursor), - NULL, NULL, - _gtk_marshal_VOID__ENUM_INT_BOOLEAN, - G_TYPE_NONE, 3, - GTK_TYPE_MOVEMENT_STEP, - G_TYPE_INT, - G_TYPE_BOOLEAN); + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (GtkLabelClass, move_cursor), + NULL, NULL, + _gtk_marshal_VOID__ENUM_INT_BOOLEAN, + G_TYPE_NONE, 3, + GTK_TYPE_MOVEMENT_STEP, + G_TYPE_INT, + G_TYPE_BOOLEAN); /** * GtkLabel::copy-clipboard: @@ -672,16 +2136,16 @@ gtk_label_class_init (GtkLabelClass *class) * which gets emitted to copy the selection to the clipboard. * * The default binding for this signal is Ctrl-c. - */ + */ signals[COPY_CLIPBOARD] = g_signal_new (I_("copy-clipboard"), - G_OBJECT_CLASS_TYPE (gobject_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (GtkLabelClass, copy_clipboard), - NULL, NULL, - NULL, - G_TYPE_NONE, 0); - + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (GtkLabelClass, copy_clipboard), + NULL, NULL, + NULL, + G_TYPE_NONE, 0); + /** * GtkLabel::activate-current-link: * @self: The label on which the signal was emitted @@ -959,7 +2423,7 @@ gtk_label_class_init (GtkLabelClass *class) /** * GtkLabel|menu.popup: * - * Opens the context menu. + * Opens the context menu. */ gtk_widget_class_install_action (widget_class, "menu.popup", NULL, gtk_label_popup_menu); @@ -978,34 +2442,34 @@ gtk_label_class_init (GtkLabelClass *class) /* Moving the insertion point */ add_move_binding (widget_class, GDK_KEY_Right, 0, - GTK_MOVEMENT_VISUAL_POSITIONS, 1); + GTK_MOVEMENT_VISUAL_POSITIONS, 1); add_move_binding (widget_class, GDK_KEY_Left, 0, - GTK_MOVEMENT_VISUAL_POSITIONS, -1); + GTK_MOVEMENT_VISUAL_POSITIONS, -1); add_move_binding (widget_class, GDK_KEY_KP_Right, 0, - GTK_MOVEMENT_VISUAL_POSITIONS, 1); - + GTK_MOVEMENT_VISUAL_POSITIONS, 1); + add_move_binding (widget_class, GDK_KEY_KP_Left, 0, - GTK_MOVEMENT_VISUAL_POSITIONS, -1); - + GTK_MOVEMENT_VISUAL_POSITIONS, -1); + add_move_binding (widget_class, GDK_KEY_f, GDK_CONTROL_MASK, - GTK_MOVEMENT_LOGICAL_POSITIONS, 1); - + GTK_MOVEMENT_LOGICAL_POSITIONS, 1); + add_move_binding (widget_class, GDK_KEY_b, GDK_CONTROL_MASK, - GTK_MOVEMENT_LOGICAL_POSITIONS, -1); - + GTK_MOVEMENT_LOGICAL_POSITIONS, -1); + add_move_binding (widget_class, GDK_KEY_Right, GDK_CONTROL_MASK, - GTK_MOVEMENT_WORDS, 1); + GTK_MOVEMENT_WORDS, 1); add_move_binding (widget_class, GDK_KEY_Left, GDK_CONTROL_MASK, - GTK_MOVEMENT_WORDS, -1); + GTK_MOVEMENT_WORDS, -1); add_move_binding (widget_class, GDK_KEY_KP_Right, GDK_CONTROL_MASK, - GTK_MOVEMENT_WORDS, 1); + GTK_MOVEMENT_WORDS, 1); add_move_binding (widget_class, GDK_KEY_KP_Left, GDK_CONTROL_MASK, - GTK_MOVEMENT_WORDS, -1); + GTK_MOVEMENT_WORDS, -1); /* select all */ gtk_widget_class_add_binding (widget_class, @@ -1020,61 +2484,61 @@ gtk_label_class_init (GtkLabelClass *class) /* unselect all */ gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_a, GDK_SHIFT_MASK | GDK_CONTROL_MASK, - "move-cursor", + "move-cursor", "(iib)", GTK_MOVEMENT_PARAGRAPH_ENDS, 0, FALSE); gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_backslash, GDK_CONTROL_MASK, - "move-cursor", + "move-cursor", "(iib)", GTK_MOVEMENT_PARAGRAPH_ENDS, 0, FALSE); add_move_binding (widget_class, GDK_KEY_f, GDK_ALT_MASK, - GTK_MOVEMENT_WORDS, 1); + GTK_MOVEMENT_WORDS, 1); add_move_binding (widget_class, GDK_KEY_b, GDK_ALT_MASK, - GTK_MOVEMENT_WORDS, -1); + GTK_MOVEMENT_WORDS, -1); add_move_binding (widget_class, GDK_KEY_Home, 0, - GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1); + GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1); add_move_binding (widget_class, GDK_KEY_End, 0, - GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1); + GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1); add_move_binding (widget_class, GDK_KEY_KP_Home, 0, - GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1); + GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1); add_move_binding (widget_class, GDK_KEY_KP_End, 0, - GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1); - + GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1); + add_move_binding (widget_class, GDK_KEY_Home, GDK_CONTROL_MASK, - GTK_MOVEMENT_BUFFER_ENDS, -1); + GTK_MOVEMENT_BUFFER_ENDS, -1); add_move_binding (widget_class, GDK_KEY_End, GDK_CONTROL_MASK, - GTK_MOVEMENT_BUFFER_ENDS, 1); + GTK_MOVEMENT_BUFFER_ENDS, 1); add_move_binding (widget_class, GDK_KEY_KP_Home, GDK_CONTROL_MASK, - GTK_MOVEMENT_BUFFER_ENDS, -1); + GTK_MOVEMENT_BUFFER_ENDS, -1); add_move_binding (widget_class, GDK_KEY_KP_End, GDK_CONTROL_MASK, - GTK_MOVEMENT_BUFFER_ENDS, 1); + GTK_MOVEMENT_BUFFER_ENDS, 1); /* copy */ gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_c, GDK_CONTROL_MASK, - "copy-clipboard", + "copy-clipboard", NULL); gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_Return, 0, - "activate-current-link", + "activate-current-link", NULL); gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_ISO_Enter, 0, - "activate-current-link", + "activate-current-link", NULL); gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_KP_Enter, 0, - "activate-current-link", + "activate-current-link", NULL); gtk_widget_class_set_css_name (widget_class, I_("label")); @@ -1140,240 +2604,6 @@ gtk_label_class_init (GtkLabelClass *class) gtk_label_activate_link_copy); } -static void -gtk_label_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GtkLabel *self = GTK_LABEL (object); - - switch (prop_id) - { - case PROP_LABEL: - gtk_label_set_label (self, g_value_get_string (value)); - break; - case PROP_ATTRIBUTES: - gtk_label_set_attributes (self, g_value_get_boxed (value)); - break; - case PROP_USE_MARKUP: - gtk_label_set_use_markup (self, g_value_get_boolean (value)); - break; - case PROP_USE_UNDERLINE: - gtk_label_set_use_underline (self, g_value_get_boolean (value)); - break; - case PROP_JUSTIFY: - gtk_label_set_justify (self, g_value_get_enum (value)); - break; - case PROP_WRAP: - gtk_label_set_wrap (self, g_value_get_boolean (value)); - break; - case PROP_WRAP_MODE: - gtk_label_set_wrap_mode (self, g_value_get_enum (value)); - break; - case PROP_SELECTABLE: - gtk_label_set_selectable (self, g_value_get_boolean (value)); - break; - case PROP_MNEMONIC_WIDGET: - gtk_label_set_mnemonic_widget (self, (GtkWidget*) g_value_get_object (value)); - break; - case PROP_ELLIPSIZE: - gtk_label_set_ellipsize (self, g_value_get_enum (value)); - break; - case PROP_WIDTH_CHARS: - gtk_label_set_width_chars (self, g_value_get_int (value)); - break; - case PROP_SINGLE_LINE_MODE: - gtk_label_set_single_line_mode (self, g_value_get_boolean (value)); - break; - case PROP_MAX_WIDTH_CHARS: - gtk_label_set_max_width_chars (self, g_value_get_int (value)); - break; - case PROP_LINES: - gtk_label_set_lines (self, g_value_get_int (value)); - break; - case PROP_XALIGN: - gtk_label_set_xalign (self, g_value_get_float (value)); - break; - case PROP_YALIGN: - gtk_label_set_yalign (self, g_value_get_float (value)); - break; - case PROP_EXTRA_MENU: - gtk_label_set_extra_menu (self, g_value_get_object (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gtk_label_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GtkLabel *self = GTK_LABEL (object); - - switch (prop_id) - { - case PROP_LABEL: - g_value_set_string (value, self->label); - break; - case PROP_ATTRIBUTES: - g_value_set_boxed (value, self->attrs); - break; - case PROP_USE_MARKUP: - g_value_set_boolean (value, self->use_markup); - break; - case PROP_USE_UNDERLINE: - g_value_set_boolean (value, self->use_underline); - break; - case PROP_JUSTIFY: - g_value_set_enum (value, self->jtype); - break; - case PROP_WRAP: - g_value_set_boolean (value, self->wrap); - break; - case PROP_WRAP_MODE: - g_value_set_enum (value, self->wrap_mode); - break; - case PROP_SELECTABLE: - g_value_set_boolean (value, gtk_label_get_selectable (self)); - break; - case PROP_MNEMONIC_KEYVAL: - g_value_set_uint (value, self->mnemonic_keyval); - break; - case PROP_MNEMONIC_WIDGET: - g_value_set_object (value, (GObject*) self->mnemonic_widget); - break; - case PROP_ELLIPSIZE: - g_value_set_enum (value, self->ellipsize); - break; - case PROP_WIDTH_CHARS: - g_value_set_int (value, gtk_label_get_width_chars (self)); - break; - case PROP_SINGLE_LINE_MODE: - g_value_set_boolean (value, gtk_label_get_single_line_mode (self)); - break; - case PROP_MAX_WIDTH_CHARS: - g_value_set_int (value, gtk_label_get_max_width_chars (self)); - break; - case PROP_LINES: - g_value_set_int (value, gtk_label_get_lines (self)); - break; - case PROP_XALIGN: - g_value_set_float (value, gtk_label_get_xalign (self)); - break; - case PROP_YALIGN: - g_value_set_float (value, gtk_label_get_yalign (self)); - break; - case PROP_EXTRA_MENU: - g_value_set_object (value, gtk_label_get_extra_menu (self)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gtk_label_init (GtkLabel *self) -{ - self->width_chars = -1; - self->max_width_chars = -1; - self->label = g_strdup (""); - self->lines = -1; - - self->xalign = 0.5; - self->yalign = 0.5; - - self->jtype = GTK_JUSTIFY_LEFT; - self->wrap = FALSE; - self->wrap_mode = PANGO_WRAP_WORD; - self->ellipsize = PANGO_ELLIPSIZE_NONE; - - self->use_underline = FALSE; - self->use_markup = FALSE; - - self->mnemonic_keyval = GDK_KEY_VoidSymbol; - self->layout = NULL; - self->text = g_strdup (""); - self->attrs = NULL; - - self->mnemonic_widget = NULL; - - self->mnemonics_visible = FALSE; -} - - -static void -gtk_label_buildable_interface_init (GtkBuildableIface *iface) -{ - buildable_parent_iface = g_type_interface_peek_parent (iface); - - iface->custom_tag_start = gtk_label_buildable_custom_tag_start; - iface->custom_finished = gtk_label_buildable_custom_finished; -} - -static const GtkBuildableParser pango_parser = -{ - gtk_pango_attribute_start_element, -}; - -static gboolean -gtk_label_buildable_custom_tag_start (GtkBuildable *buildable, - GtkBuilder *builder, - GObject *child, - const char *tagname, - GtkBuildableParser *parser, - gpointer *data) -{ - if (buildable_parent_iface->custom_tag_start (buildable, builder, child, - tagname, parser, data)) - return TRUE; - - if (strcmp (tagname, "attributes") == 0) - { - GtkPangoAttributeParserData *parser_data; - - parser_data = g_slice_new0 (GtkPangoAttributeParserData); - parser_data->builder = g_object_ref (builder); - parser_data->object = (GObject *) g_object_ref (buildable); - *parser = pango_parser; - *data = parser_data; - return TRUE; - } - return FALSE; -} - -static void -gtk_label_buildable_custom_finished (GtkBuildable *buildable, - GtkBuilder *builder, - GObject *child, - const char *tagname, - gpointer user_data) -{ - GtkPangoAttributeParserData *data = user_data; - - buildable_parent_iface->custom_finished (buildable, builder, child, - tagname, user_data); - - if (strcmp (tagname, "attributes") == 0) - { - if (data->attrs) - { - gtk_label_set_attributes (GTK_LABEL (buildable), data->attrs); - pango_attr_list_unref (data->attrs); - } - - g_object_unref (data->object); - g_object_unref (data->builder); - g_slice_free (GtkPangoAttributeParserData, data); - } -} - - /** * gtk_label_new: * @str: (nullable): The text of the label @@ -1405,15 +2635,15 @@ gtk_label_new (const char *str) * * If characters in @str are preceded by an underscore, they are * underlined. If you need a literal underscore character in a label, use - * '__' (two underscores). The first underlined character represents a - * keyboard accelerator called a mnemonic. The mnemonic key can be used + * '__' (two underscores). The first underlined character represents a + * keyboard accelerator called a mnemonic. The mnemonic key can be used * to activate another widget, chosen automatically, or explicitly using * gtk_label_set_mnemonic_widget(). - * - * If gtk_label_set_mnemonic_widget() is not called, then the first - * activatable ancestor of the #GtkLabel will be chosen as the mnemonic - * widget. For instance, if the label is inside a button or menu item, - * the button or menu item will automatically become the mnemonic widget + * + * If gtk_label_set_mnemonic_widget() is not called, then the first + * activatable ancestor of the #GtkLabel will be chosen as the mnemonic + * widget. For instance, if the label is inside a button or menu item, + * the button or menu item will automatically become the mnemonic widget * and be activated by the mnemonic. * * Returns: the new #GtkLabel @@ -1431,38 +2661,34 @@ gtk_label_new_with_mnemonic (const char *str) return GTK_WIDGET (self); } -static gboolean -gtk_label_mnemonic_activate (GtkWidget *widget, - gboolean group_cycling) +static void +_gtk_label_mnemonics_visible_apply_recursively (GtkWidget *widget, + gboolean visible) { - GtkLabel *self = GTK_LABEL (widget); - GtkWidget *parent; - - if (self->mnemonic_widget) - return gtk_widget_mnemonic_activate (self->mnemonic_widget, group_cycling); - - /* Try to find the widget to activate by traversing the - * widget's ancestry. - */ - parent = gtk_widget_get_parent (widget); - - if (GTK_IS_NOTEBOOK (parent)) - return FALSE; - - while (parent) + if (GTK_IS_LABEL (widget)) { - if (gtk_widget_get_can_focus (parent) || - (!group_cycling && gtk_widget_can_activate (parent)) || - GTK_IS_NOTEBOOK (gtk_widget_get_parent (parent))) - return gtk_widget_mnemonic_activate (parent, group_cycling); - parent = gtk_widget_get_parent (parent); + GtkLabel *self = GTK_LABEL (widget); + + if (self->mnemonics_visible != visible) + { + self->mnemonics_visible = visible; + gtk_label_recalculate (self); + } } + else + { + GtkWidget *child; - /* barf if there was nothing to activate */ - g_warning ("Couldn't find a target for a mnemonic activation."); - gtk_widget_error_bell (widget); + for (child = gtk_widget_get_first_child (widget); + child; + child = gtk_widget_get_next_sibling (child)) + { + if (GTK_IS_NATIVE (child)) + continue; - return FALSE; + _gtk_label_mnemonics_visible_apply_recursively (child, visible); + } + } } static void @@ -1521,8 +2747,8 @@ gtk_label_setup_mnemonic (GtkLabel *self) g_object_get (native, "mnemonics-visible", &mnemonics_visible, NULL); self->mnemonics_visible = mnemonics_visible; - connected = - GPOINTER_TO_INT (g_object_get_qdata (G_OBJECT (native), quark_mnemonics_visible_connected)); + connected = GPOINTER_TO_INT (g_object_get_qdata (G_OBJECT (native), + quark_mnemonics_visible_connected)); if (!connected) { @@ -1537,60 +2763,8 @@ gtk_label_setup_mnemonic (GtkLabel *self) } static void -gtk_label_root (GtkWidget *widget) -{ - GtkLabel *self = GTK_LABEL (widget); - - GTK_WIDGET_CLASS (gtk_label_parent_class)->root (widget); - - gtk_label_setup_mnemonic (self); - - /* The PangoContext is replaced when the display changes, so clear the layouts */ - gtk_label_clear_layout (GTK_LABEL (widget)); -} - -static void -gtk_label_unroot (GtkWidget *widget) -{ - GtkLabel *self = GTK_LABEL (widget); - - gtk_label_setup_mnemonic (self); - - GTK_WIDGET_CLASS (gtk_label_parent_class)->unroot (widget); -} - -void -_gtk_label_mnemonics_visible_apply_recursively (GtkWidget *widget, - gboolean visible) -{ - if (GTK_IS_LABEL (widget)) - { - GtkLabel *self = GTK_LABEL (widget); - - if (self->mnemonics_visible != visible) - { - self->mnemonics_visible = visible; - gtk_label_recalculate (self); - } - } - else - { - GtkWidget *child; - - for (child = gtk_widget_get_first_child (widget); - child; - child = gtk_widget_get_next_sibling (child)) - { - if (GTK_IS_NATIVE (child)) - continue; - - _gtk_label_mnemonics_visible_apply_recursively (child, visible); - } - } -} -static void label_mnemonic_widget_weak_notify (gpointer data, - GObject *where_the_object_was) + GObject *where_the_object_was) { GtkLabel *self = data; @@ -1613,14 +2787,14 @@ label_mnemonic_widget_weak_notify (gpointer data, * (i.e. when the target is a #GtkEntry next to the label) you need to * set it explicitly using this function. * - * The target widget will be accelerated by emitting the - * GtkWidget::mnemonic-activate signal on it. The default handler for - * this signal will activate the widget if there are no mnemonic collisions + * The target widget will be accelerated by emitting the + * GtkWidget::mnemonic-activate signal on it. The default handler for + * this signal will activate the widget if there are no mnemonic collisions * and toggle focus between the colliding widgets otherwise. **/ void gtk_label_set_mnemonic_widget (GtkLabel *self, - GtkWidget *widget) + GtkWidget *widget) { g_return_if_fail (GTK_IS_LABEL (self)); @@ -2106,14 +3280,6 @@ xml_isspace (char c) return (c == ' ' || c == '\t' || c == '\n' || c == '\r'); } -static void -link_free (GtkLabelLink *link) -{ - gtk_css_node_set_parent (link->cssnode, NULL); - g_free (link->uri); - g_free (link->title); -} - static gboolean parse_uri_markup (GtkLabel *self, const char *str, @@ -2364,7 +3530,6 @@ no_uline: if (text) gtk_label_set_text_internal (self, text); - g_clear_pointer (&self->markup_attrs, pango_attr_list_unref); self->markup_attrs = attrs; @@ -2470,11 +3635,11 @@ gtk_label_set_markup_with_mnemonic (GtkLabel *self, /** * gtk_label_get_text: * @self: a #GtkLabel - * + * * Fetches the text from a label widget, as displayed on the * screen. This does not include any embedded underlines * indicating mnemonics or Pango markup. (See gtk_label_get_label()) - * + * * Returns: the text in the label widget. This is the internal * string used by the label, and must not be modified. **/ @@ -2500,7 +3665,7 @@ gtk_label_get_text (GtkLabel *self) */ void gtk_label_set_justify (GtkLabel *self, - GtkJustification jtype) + GtkJustification jtype) { g_return_if_fail (GTK_IS_LABEL (self)); g_return_if_fail (jtype >= GTK_JUSTIFY_LEFT && jtype <= GTK_JUSTIFY_FILL); @@ -2511,7 +3676,7 @@ gtk_label_set_justify (GtkLabel *self, /* No real need to be this drastic, but easier than duplicating the code */ gtk_label_clear_layout (self); - + g_object_notify_by_pspec (G_OBJECT (self), label_props[PROP_JUSTIFY]); gtk_widget_queue_resize (GTK_WIDGET (self)); } @@ -2538,12 +3703,12 @@ gtk_label_get_justify (GtkLabel *self) * @self: a #GtkLabel * @mode: a #PangoEllipsizeMode * - * Sets the mode used to ellipsize (add an ellipsis: "...") to the text + * Sets the mode used to ellipsize (add an ellipsis: "...") to the text * if there is not enough space to render the entire string. **/ void gtk_label_set_ellipsize (GtkLabel *self, - PangoEllipsizeMode mode) + PangoEllipsizeMode mode) { g_return_if_fail (GTK_IS_LABEL (self)); g_return_if_fail (mode >= PANGO_ELLIPSIZE_NONE && mode <= PANGO_ELLIPSIZE_END); @@ -2580,12 +3745,12 @@ gtk_label_get_ellipsize (GtkLabel *self) * gtk_label_set_width_chars: * @self: a #GtkLabel * @n_chars: the new desired width, in characters. - * + * * Sets the desired width in characters of @label to @n_chars. **/ void gtk_label_set_width_chars (GtkLabel *self, - int n_chars) + int n_chars) { g_return_if_fail (GTK_IS_LABEL (self)); @@ -2600,10 +3765,10 @@ gtk_label_set_width_chars (GtkLabel *self, /** * gtk_label_get_width_chars: * @self: a #GtkLabel - * + * * Retrieves the desired width of @label, in characters. See * gtk_label_set_width_chars(). - * + * * Returns: the width of the label in characters. **/ int @@ -2618,12 +3783,12 @@ gtk_label_get_width_chars (GtkLabel *self) * gtk_label_set_max_width_chars: * @self: a #GtkLabel * @n_chars: the new desired maximum width, in characters. - * + * * Sets the desired maximum width in characters of @label to @n_chars. **/ void gtk_label_set_max_width_chars (GtkLabel *self, - int n_chars) + int n_chars) { g_return_if_fail (GTK_IS_LABEL (self)); @@ -2639,10 +3804,10 @@ gtk_label_set_max_width_chars (GtkLabel *self, /** * gtk_label_get_max_width_chars: * @self: a #GtkLabel - * + * * Retrieves the desired maximum width of @label, in characters. See * gtk_label_set_width_chars(). - * + * * Returns: the maximum width of the label in characters. **/ int @@ -2744,194 +3909,11 @@ gtk_label_get_wrap_mode (GtkLabel *self) } static void -gtk_label_dispose (GObject *object) -{ - GtkLabel *self = GTK_LABEL (object); - - gtk_label_set_mnemonic_widget (self, NULL); - - G_OBJECT_CLASS (gtk_label_parent_class)->dispose (object); -} - -static void -gtk_label_finalize (GObject *object) -{ - GtkLabel *self = GTK_LABEL (object); - - g_free (self->label); - g_free (self->text); - - g_clear_object (&self->layout); - g_clear_pointer (&self->attrs, pango_attr_list_unref); - g_clear_pointer (&self->markup_attrs, pango_attr_list_unref); - - if (self->select_info) - g_object_unref (self->select_info->provider); - - gtk_label_clear_links (self); - g_free (self->select_info); - - g_clear_pointer (&self->popup_menu, gtk_widget_unparent); - g_clear_object (&self->extra_menu); - - G_OBJECT_CLASS (gtk_label_parent_class)->finalize (object); -} - -static void gtk_label_clear_layout (GtkLabel *self) { g_clear_object (&self->layout); } -/** - * gtk_label_get_measuring_layout: - * @self: the label - * @existing_layout: %NULL or an existing layout already in use. - * @width: the width to measure with in pango units, or -1 for infinite - * - * Gets a layout that can be used for measuring sizes. The returned - * layout will be identical to the label’s layout except for the - * layout’s width, which will be set to @width. Do not modify the returned - * layout. - * - * Returns: a new reference to a pango layout - **/ -static PangoLayout * -gtk_label_get_measuring_layout (GtkLabel *self, - PangoLayout *existing_layout, - int width) -{ - PangoLayout *copy; - - if (existing_layout != NULL) - { - if (existing_layout != self->layout) - { - pango_layout_set_width (existing_layout, width); - return existing_layout; - } - - g_object_unref (existing_layout); - } - - gtk_label_ensure_layout (self); - - if (pango_layout_get_width (self->layout) == width) - { - g_object_ref (self->layout); - return self->layout; - } - - /* We can use the label's own layout if we're not allocated a size yet, - * because we don't need it to be properly setup at that point. - * This way we can make use of caching upon the label's creation. - */ - if (gtk_widget_get_width (GTK_WIDGET (self)) <= 1) - { - g_object_ref (self->layout); - pango_layout_set_width (self->layout, width); - return self->layout; - } - - /* oftentimes we want to measure a width that is far wider than the current width, - * even though the layout would not change if we made it wider. In that case, we - * can just return the current layout, because for measuring purposes, it will be - * identical. - */ - if (!pango_layout_is_wrapped (self->layout) && - !pango_layout_is_ellipsized (self->layout)) - { - PangoRectangle rect; - - if (width == -1) - return g_object_ref (self->layout); - - pango_layout_get_extents (self->layout, NULL, &rect); - if (rect.width <= width) - return g_object_ref (self->layout); - } - - copy = pango_layout_copy (self->layout); - pango_layout_set_width (copy, width); - return copy; -} - -static void -gtk_label_update_layout_attributes (GtkLabel *self, - PangoAttrList *style_attrs) -{ - GtkWidget *widget = GTK_WIDGET (self); - GtkCssStyle *style; - PangoAttrList *attrs; - - if (self->layout == NULL) - { - pango_attr_list_unref (style_attrs); - return; - } - - if (self->select_info && self->select_info->links) - { - guint i; - - attrs = pango_attr_list_new (); - - for (i = 0; i < self->select_info->n_links; i++) - { - const GtkLabelLink *link = &self->select_info->links[i]; - const GdkRGBA *link_color; - PangoAttrList *link_attrs; - PangoAttribute *attr; - - style = gtk_css_node_get_style (link->cssnode); - link_attrs = gtk_css_style_get_pango_attributes (style); - if (link_attrs) - { - GSList *attributes = pango_attr_list_get_attributes (link_attrs); - GSList *l; - for (l = attributes; l; l = l->next) - { - attr = l->data; - - attr->start_index = link->start; - attr->end_index = link->end; - pango_attr_list_insert (attrs, attr); - } - g_slist_free (attributes); - } - - link_color = gtk_css_color_value_get_rgba (style->core->color); - attr = pango_attr_foreground_new (link_color->red * 65535, - link_color->green * 65535, - link_color->blue * 65535); - attr->start_index = link->start; - attr->end_index = link->end; - pango_attr_list_insert (attrs, attr); - - pango_attr_list_unref (link_attrs); - } - } - else - attrs = NULL; - - style = gtk_css_node_get_style (gtk_widget_get_css_node (widget)); - if (!style_attrs) - style_attrs = gtk_css_style_get_pango_attributes (style); - - if (style_attrs) - { - attrs = _gtk_pango_attr_list_merge (attrs, style_attrs); - pango_attr_list_unref (style_attrs); - } - - attrs = _gtk_pango_attr_list_merge (attrs, self->markup_attrs); - attrs = _gtk_pango_attr_list_merge (attrs, self->attrs); - - pango_layout_set_attributes (self->layout, attrs); - - pango_attr_list_unref (attrs); -} - static void gtk_label_ensure_layout (GtkLabel *self) { @@ -2977,564 +3959,6 @@ gtk_label_ensure_layout (GtkLabel *self) pango_layout_set_width (self->layout, gtk_widget_get_width (GTK_WIDGET (self)) * PANGO_SCALE); } -static GtkSizeRequestMode -gtk_label_get_request_mode (GtkWidget *widget) -{ - GtkLabel *self = GTK_LABEL (widget); - - if (self->wrap) - return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH; - - return GTK_SIZE_REQUEST_CONSTANT_SIZE; -} - - -static void -get_height_for_width (GtkLabel *self, - int width, - int *minimum_height, - int *natural_height, - int *minimum_baseline, - int *natural_baseline) -{ - PangoLayout *layout; - int text_height, baseline; - - layout = gtk_label_get_measuring_layout (self, NULL, width * PANGO_SCALE); - - pango_layout_get_pixel_size (layout, NULL, &text_height); - - *minimum_height = text_height; - *natural_height = text_height; - - baseline = pango_layout_get_baseline (layout) / PANGO_SCALE; - *minimum_baseline = baseline; - *natural_baseline = baseline; - - g_object_unref (layout); -} - -static int -get_char_pixels (GtkWidget *self, - PangoLayout *layout) -{ - PangoContext *context; - PangoFontMetrics *metrics; - int char_width, digit_width; - - context = pango_layout_get_context (layout); - metrics = pango_context_get_metrics (context, - pango_context_get_font_description (context), - pango_context_get_language (context)); - char_width = pango_font_metrics_get_approximate_char_width (metrics); - digit_width = pango_font_metrics_get_approximate_digit_width (metrics); - pango_font_metrics_unref (metrics); - - return MAX (char_width, digit_width);; -} - -static void -gtk_label_get_preferred_layout_size (GtkLabel *self, - PangoRectangle *smallest, - PangoRectangle *widest, - int *smallest_baseline, - int *widest_baseline) -{ - PangoLayout *layout; - int char_pixels; - - /* "width-chars" Hard-coded minimum width: - * - minimum size should be MAX (width-chars, strlen ("...")); - * - natural size should be MAX (width-chars, strlen (self->text)); - * - * "max-width-chars" User specified maximum size requisition - * - minimum size should be MAX (width-chars, 0) - * - natural size should be MIN (max-width-chars, strlen (self->text)) - * - * For ellipsizing labels; if max-width-chars is specified: either it is used as - * a minimum size or the label text as a minimum size (natural size still overflows). - * - * For wrapping labels; A reasonable minimum size is useful to naturally layout - * interfaces automatically. In this case if no "width-chars" is specified, the minimum - * width will default to the wrap guess that gtk_label_ensure_layout() does. - */ - - /* Start off with the pixel extents of an as-wide-as-possible layout */ - layout = gtk_label_get_measuring_layout (self, NULL, -1); - - if (self->width_chars > -1 || self->max_width_chars > -1) - char_pixels = get_char_pixels (GTK_WIDGET (self), layout); - else - char_pixels = 0; - - pango_layout_get_extents (layout, NULL, widest); - widest->width = MAX (widest->width, char_pixels * self->width_chars); - widest->x = widest->y = 0; - *widest_baseline = pango_layout_get_baseline (layout) / PANGO_SCALE; - - if (self->ellipsize || self->wrap) - { - /* a layout with width 0 will be as small as humanly possible */ - layout = gtk_label_get_measuring_layout (self, - layout, - self->width_chars > -1 ? char_pixels * self->width_chars - : 0); - - pango_layout_get_extents (layout, NULL, smallest); - smallest->width = MAX (smallest->width, char_pixels * self->width_chars); - smallest->x = smallest->y = 0; - - *smallest_baseline = pango_layout_get_baseline (layout) / PANGO_SCALE; - - if (self->max_width_chars > -1 && widest->width > char_pixels * self->max_width_chars) - { - layout = gtk_label_get_measuring_layout (self, - layout, - MAX (smallest->width, char_pixels * self->max_width_chars)); - pango_layout_get_extents (layout, NULL, widest); - widest->width = MAX (widest->width, char_pixels * self->width_chars); - widest->x = widest->y = 0; - - *widest_baseline = pango_layout_get_baseline (layout) / PANGO_SCALE; - } - - if (widest->width < smallest->width) - { - *smallest = *widest; - *smallest_baseline = *widest_baseline; - } - } - else - { - *smallest = *widest; - *smallest_baseline = *widest_baseline; - } - - g_object_unref (layout); -} - -static void -gtk_label_get_preferred_size (GtkWidget *widget, - GtkOrientation orientation, - int *minimum_size, - int *natural_size, - int *minimum_baseline, - int *natural_baseline) -{ - GtkLabel *self = GTK_LABEL (widget); - PangoRectangle widest_rect; - PangoRectangle smallest_rect; - int smallest_baseline; - int widest_baseline; - - gtk_label_get_preferred_layout_size (self, - &smallest_rect, &widest_rect, - &smallest_baseline, &widest_baseline); - - widest_rect.width = PANGO_PIXELS_CEIL (widest_rect.width); - widest_rect.height = PANGO_PIXELS_CEIL (widest_rect.height); - - smallest_rect.width = PANGO_PIXELS_CEIL (smallest_rect.width); - smallest_rect.height = PANGO_PIXELS_CEIL (smallest_rect.height); - - if (orientation == GTK_ORIENTATION_HORIZONTAL) - { - /* Normal desired width */ - *minimum_size = smallest_rect.width; - *natural_size = widest_rect.width; - - if (minimum_baseline) - *minimum_baseline = -1; - - if (natural_baseline) - *natural_baseline = -1; - } - else /* GTK_ORIENTATION_VERTICAL */ - { - if (smallest_rect.height < widest_rect.height) - { - *minimum_size = smallest_rect.height; - *natural_size = widest_rect.height; - if (minimum_baseline) - *minimum_baseline = smallest_baseline; - if (natural_baseline) - *natural_baseline = widest_baseline; - } - else - { - *minimum_size = widest_rect.height; - *natural_size = smallest_rect.height; - if (minimum_baseline) - *minimum_baseline = widest_baseline; - if (natural_baseline) - *natural_baseline = smallest_baseline; - } - } -} - -static void -gtk_label_measure (GtkWidget *widget, - GtkOrientation orientation, - int for_size, - int *minimum, - int *natural, - int *minimum_baseline, - int *natural_baseline) -{ - GtkLabel *self = GTK_LABEL (widget); - - if (orientation == GTK_ORIENTATION_VERTICAL && for_size != -1 && self->wrap) - { - gtk_label_clear_layout (self); - - get_height_for_width (self, for_size, minimum, natural, minimum_baseline, natural_baseline); - } - else - gtk_label_get_preferred_size (widget, orientation, minimum, natural, minimum_baseline, natural_baseline); -} - -static void -get_layout_location (GtkLabel *self, - int *xp, - int *yp) -{ - GtkWidget *widget = GTK_WIDGET (self); - int layout_width, layout_height, x, y; - float xalign, yalign; - PangoRectangle logical; - int baseline, layout_baseline, baseline_offset; - int widget_width, widget_height; - - xalign = self->xalign; - yalign = self->yalign; - - if (_gtk_widget_get_direction (widget) != GTK_TEXT_DIR_LTR) - xalign = 1.0 - xalign; - - pango_layout_get_pixel_extents (self->layout, NULL, &logical); - - layout_width = logical.width; - layout_height = logical.height; - - widget_width = gtk_widget_get_width (widget); - widget_height = gtk_widget_get_height (widget); - - baseline = gtk_widget_get_allocated_baseline (widget); - - x = floor ((xalign * (widget_width - layout_width)) - logical.x); - - baseline_offset = 0; - if (baseline != -1) - { - layout_baseline = pango_layout_get_baseline (self->layout) / PANGO_SCALE; - baseline_offset = baseline - layout_baseline; - yalign = 0.0; /* Can't support yalign while baseline aligning */ - } - - y = floor ((widget_height - layout_height) * yalign) + baseline_offset; - - if (xp) - *xp = x; - - if (yp) - *yp = y; -} - -static void -gtk_label_size_allocate (GtkWidget *widget, - int width, - int height, - int baseline) -{ - GtkLabel *self = GTK_LABEL (widget); - - if (self->layout) - { - if (self->ellipsize || self->wrap) - pango_layout_set_width (self->layout, width * PANGO_SCALE); - else - pango_layout_set_width (self->layout, -1); - } - - if (self->popup_menu) - gtk_popover_present (GTK_POPOVER (self->popup_menu)); -} - -static void -gtk_label_update_cursor (GtkLabel *self) -{ - GtkWidget *widget = GTK_WIDGET (self); - - if (!self->select_info) - return; - - if (gtk_widget_is_sensitive (widget)) - { - if (self->select_info->active_link) - gtk_widget_set_cursor_from_name (widget, "pointer"); - else if (self->select_info->selectable) - gtk_widget_set_cursor_from_name (widget, "text"); - else - gtk_widget_set_cursor (widget, NULL); - } - else - gtk_widget_set_cursor (widget, NULL); -} - -static void -update_link_state (GtkLabel *self) -{ - GtkStateFlags state; - guint i; - - if (!self->select_info) - return; - - for (i = 0; i < self->select_info->n_links; i++) - { - const GtkLabelLink *link = &self->select_info->links[i]; - - state = gtk_widget_get_state_flags (GTK_WIDGET (self)); - if (link->visited) - state |= GTK_STATE_FLAG_VISITED; - else - state |= GTK_STATE_FLAG_LINK; - if (link == self->select_info->active_link) - { - if (self->select_info->link_clicked) - state |= GTK_STATE_FLAG_ACTIVE; - else - state |= GTK_STATE_FLAG_PRELIGHT; - } - gtk_css_node_set_state (link->cssnode, state); - } -} - -static void -gtk_label_state_flags_changed (GtkWidget *widget, - GtkStateFlags prev_state) -{ - GtkLabel *self = GTK_LABEL (widget); - - if (self->select_info) - { - if (!gtk_widget_is_sensitive (widget)) - gtk_label_select_region (self, 0, 0); - - gtk_label_update_cursor (self); - update_link_state (self); - } - - if (GTK_WIDGET_CLASS (gtk_label_parent_class)->state_flags_changed) - GTK_WIDGET_CLASS (gtk_label_parent_class)->state_flags_changed (widget, prev_state); -} - -static void -gtk_label_css_changed (GtkWidget *widget, - GtkCssStyleChange *change) -{ - GtkLabel *self = GTK_LABEL (widget); - gboolean attrs_affected; - PangoAttrList *new_attrs = NULL; - - GTK_WIDGET_CLASS (gtk_label_parent_class)->css_changed (widget, change); - - if (gtk_css_style_change_affects (change, GTK_CSS_AFFECTS_TEXT_ATTRS)) - { - new_attrs = gtk_css_style_get_pango_attributes (gtk_css_style_change_get_new_style (change)); - attrs_affected = (self->layout && pango_layout_get_attributes (self->layout)) || - new_attrs; - } - else - attrs_affected = FALSE; - - if (change == NULL || attrs_affected || (self->select_info && self->select_info->links)) - { - gtk_label_update_layout_attributes (self, new_attrs); - - if (attrs_affected) - gtk_widget_queue_draw (widget); - } -} - -static PangoDirection -get_cursor_direction (GtkLabel *self) -{ - GSList *l; - - g_assert (self->select_info); - - gtk_label_ensure_layout (self); - - for (l = pango_layout_get_lines_readonly (self->layout); l; l = l->next) - { - PangoLayoutLine *line = l->data; - - /* If self->select_info->selection_end is at the very end of - * the line, we don't know if the cursor is on this line or - * the next without looking ahead at the next line. (End - * of paragraph is different from line break.) But it's - * definitely in this paragraph, which is good enough - * to figure out the resolved direction. - */ - if (line->start_index + line->length >= self->select_info->selection_end) - return line->resolved_dir; - } - - return PANGO_DIRECTION_LTR; -} - -static GtkLabelLink * -gtk_label_get_focus_link (GtkLabel *self, - int *out_index) -{ - GtkLabelSelectionInfo *info = self->select_info; - int link_index; - - if (!info || - info->selection_anchor != info->selection_end) - goto nope; - - link_index = _gtk_label_get_link_at (self, info->selection_anchor); - - if (link_index != -1) - { - if (out_index) - *out_index = link_index; - - return &info->links[link_index]; - } - -nope: - if (out_index) - *out_index = -1; - return NULL; -} - -#define GRAPHENE_RECT_FROM_RECT(_r) (GRAPHENE_RECT_INIT ((_r)->x, (_r)->y, (_r)->width, (_r)->height)) - -static void -gtk_label_snapshot (GtkWidget *widget, - GtkSnapshot *snapshot) -{ - GtkLabel *self = GTK_LABEL (widget); - GtkLabelSelectionInfo *info; - GtkStyleContext *context; - int lx, ly; - int width, height; - - if (!self->text || (*self->text == '\0')) - return; - - gtk_label_ensure_layout (self); - - context = _gtk_widget_get_style_context (widget); - get_layout_location (self, &lx, &ly); - - gtk_snapshot_render_layout (snapshot, context, lx, ly, self->layout); - - info = self->select_info; - if (!info) - return; - - width = gtk_widget_get_width (widget); - height = gtk_widget_get_height (widget); - - if (info->selection_anchor != info->selection_end) - { - int range[2]; - cairo_region_t *range_clip; - cairo_rectangle_int_t clip_rect; - int i; - - range[0] = MIN (info->selection_anchor, info->selection_end); - range[1] = MAX (info->selection_anchor, info->selection_end); - - gtk_style_context_save_to_node (context, info->selection_node); - - range_clip = gdk_pango_layout_get_clip_region (self->layout, lx, ly, range, 1); - for (i = 0; i < cairo_region_num_rectangles (range_clip); i++) - { - cairo_region_get_rectangle (range_clip, i, &clip_rect); - - gtk_snapshot_push_clip (snapshot, &GRAPHENE_RECT_FROM_RECT (&clip_rect)); - gtk_snapshot_render_background (snapshot, context, 0, 0, width, height); - gtk_snapshot_render_layout (snapshot, context, lx, ly, self->layout); - gtk_snapshot_pop (snapshot); - } - - cairo_region_destroy (range_clip); - - gtk_style_context_restore (context); - } - else - { - GtkLabelLink *focus_link; - GtkLabelLink *active_link; - int range[2]; - cairo_region_t *range_clip; - cairo_rectangle_int_t clip_rect; - int i; - GdkRectangle rect; - - if (info->selectable && - gtk_widget_has_focus (widget) && - gtk_widget_is_drawable (widget)) - { - PangoDirection cursor_direction; - - cursor_direction = get_cursor_direction (self); - gtk_snapshot_render_insertion_cursor (snapshot, context, - lx, ly, - self->layout, self->select_info->selection_end, - cursor_direction); - } - - focus_link = gtk_label_get_focus_link (self, NULL); - active_link = info->active_link; - - if (active_link) - { - range[0] = active_link->start; - range[1] = active_link->end; - - gtk_style_context_save_to_node (context, active_link->cssnode); - - range_clip = gdk_pango_layout_get_clip_region (self->layout, lx, ly, range, 1); - for (i = 0; i < cairo_region_num_rectangles (range_clip); i++) - { - cairo_region_get_rectangle (range_clip, i, &clip_rect); - - gtk_snapshot_push_clip (snapshot, &GRAPHENE_RECT_FROM_RECT (&clip_rect)); - gtk_snapshot_render_background (snapshot, context, 0, 0, width, height); - gtk_snapshot_render_layout (snapshot, context, lx, ly, self->layout); - gtk_snapshot_pop (snapshot); - } - - cairo_region_destroy (range_clip); - - gtk_style_context_restore (context); - } - - if (focus_link && gtk_widget_has_visible_focus (widget)) - { - range[0] = focus_link->start; - range[1] = focus_link->end; - - gtk_style_context_save_to_node (context, focus_link->cssnode); - - range_clip = gdk_pango_layout_get_clip_region (self->layout, lx, ly, range, 1); - cairo_region_get_extents (range_clip, &rect); - - gtk_snapshot_render_focus (snapshot, context, rect.x, rect.y, rect.width, rect.height); - - cairo_region_destroy (range_clip); - - gtk_style_context_restore (context); - } - } -} - /** * gtk_label_set_text_with_mnemonic: * @self: a #GtkLabel @@ -3567,124 +3991,55 @@ gtk_label_set_text_with_mnemonic (GtkLabel *self, g_object_thaw_notify (G_OBJECT (self)); } -static void -gtk_label_unrealize (GtkWidget *widget) +static int +gtk_label_move_forward_word (GtkLabel *self, + int start) { - GtkLabel *self = GTK_LABEL (widget); + int new_pos = g_utf8_pointer_to_offset (self->text, self->text + start); + int length; - if (self->select_info && - self->select_info->provider) + length = g_utf8_strlen (self->text, -1); + if (new_pos < length) { - GdkClipboard *clipboard = gtk_widget_get_primary_clipboard (widget); - - if (gdk_clipboard_get_content (clipboard) == self->select_info->provider) - gdk_clipboard_set_content (clipboard, NULL); - } - - GTK_WIDGET_CLASS (gtk_label_parent_class)->unrealize (widget); -} - -static gboolean -get_layout_index (GtkLabel *self, - int x, - int y, - int *index) -{ - int trailing = 0; - const char *cluster; - const char *cluster_end; - gboolean inside; - int lx, ly; - - *index = 0; - - gtk_label_ensure_layout (self); - get_layout_location (self, &lx, &ly); - - /* Translate x/y to layout position */ - x -= lx; - y -= ly; + const PangoLogAttr *log_attrs; + int n_attrs; - x *= PANGO_SCALE; - y *= PANGO_SCALE; + gtk_label_ensure_layout (self); - inside = pango_layout_xy_to_index (self->layout, - x, y, - index, &trailing); + log_attrs = pango_layout_get_log_attrs_readonly (self->layout, &n_attrs); - cluster = self->text + *index; - cluster_end = cluster; - while (trailing) - { - cluster_end = g_utf8_next_char (cluster_end); - --trailing; + /* Find the next word end */ + new_pos++; + while (new_pos < n_attrs && !log_attrs[new_pos].is_word_end) + new_pos++; } - *index += (cluster_end - cluster); - - return inside; + return g_utf8_offset_to_pointer (self->text, new_pos) - self->text; } -static gboolean -range_is_in_ellipsis_full (GtkLabel *self, - int range_start, - int range_end, - int *ellipsis_start, - int *ellipsis_end) +static int +gtk_label_move_backward_word (GtkLabel *self, + int start) { - PangoLayoutIter *iter; - gboolean in_ellipsis; - - if (!self->ellipsize) - return FALSE; - - gtk_label_ensure_layout (self); + int new_pos = g_utf8_pointer_to_offset (self->text, self->text + start); - if (!pango_layout_is_ellipsized (self->layout)) - return FALSE; - - iter = pango_layout_get_iter (self->layout); - - in_ellipsis = FALSE; - - do { - PangoLayoutRun *run; - - run = pango_layout_iter_get_run_readonly (iter); - if (run) - { - PangoItem *item; + if (new_pos > 0) + { + const PangoLogAttr *log_attrs; + int n_attrs; - item = ((PangoGlyphItem*)run)->item; + gtk_label_ensure_layout (self); - if (item->offset <= range_start && range_end <= item->offset + item->length) - { - if (item->analysis.flags & PANGO_ANALYSIS_FLAG_IS_ELLIPSIS) - { - if (ellipsis_start) - *ellipsis_start = item->offset; - if (ellipsis_end) - *ellipsis_end = item->offset + item->length; - in_ellipsis = TRUE; - } - break; - } - else if (item->offset + item->length >= range_end) - break; - } - } while (pango_layout_iter_next_run (iter)); + log_attrs = pango_layout_get_log_attrs_readonly (self->layout, &n_attrs); - pango_layout_iter_free (iter); + new_pos -= 1; - return in_ellipsis; -} + /* Find the previous word beginning */ + while (new_pos > 0 && !log_attrs[new_pos].is_word_start) + new_pos--; + } -static gboolean -range_is_in_ellipsis (GtkLabel *self, - int range_start, - int range_end) -{ - return range_is_in_ellipsis_full (self, range_start, range_end, NULL, NULL); + return g_utf8_offset_to_pointer (self->text, new_pos) - self->text; } static void @@ -3696,9 +4051,9 @@ gtk_label_select_word (GtkLabel *self) int end_index = gtk_label_move_forward_word (self, self->select_info->selection_end); min = MIN (self->select_info->selection_anchor, - self->select_info->selection_end); + self->select_info->selection_end); max = MAX (self->select_info->selection_anchor, - self->select_info->selection_end); + self->select_info->selection_end); min = MIN (min, start_index); max = MAX (max, end_index); @@ -3706,207 +4061,6 @@ gtk_label_select_word (GtkLabel *self) gtk_label_select_region_index (self, min, max); } -static gboolean -gtk_label_grab_focus (GtkWidget *widget) -{ - GtkLabel *self = GTK_LABEL (widget); - gboolean select_on_focus; - GtkWidget *prev_focus; - - if (self->select_info == NULL) - return FALSE; - - prev_focus = gtk_root_get_focus (gtk_widget_get_root (widget)); - - if (!GTK_WIDGET_CLASS (gtk_label_parent_class)->grab_focus (widget)) - return FALSE; - - if (self->select_info->selectable) - { - g_object_get (gtk_widget_get_settings (widget), - "gtk-label-select-on-focus", - &select_on_focus, - NULL); - - if (select_on_focus && !self->in_click && - !(prev_focus && gtk_widget_is_ancestor (prev_focus, widget))) - gtk_label_select_region (self, 0, -1); - } - else - { - if (self->select_info->links && !self->in_click && - !(prev_focus && gtk_widget_is_ancestor (prev_focus, widget))) - { - guint i; - - for (i = 0; i < self->select_info->n_links; i++) - { - const GtkLabelLink *link = &self->select_info->links[i]; - - if (!range_is_in_ellipsis (self, link->start, link->end)) - { - self->select_info->selection_anchor = link->start; - self->select_info->selection_end = link->start; - break; - } - } - } - } - - return TRUE; -} - -static gboolean -gtk_label_focus (GtkWidget *widget, - GtkDirectionType direction) -{ - GtkLabel *self = GTK_LABEL (widget); - GtkLabelSelectionInfo *info = self->select_info; - GtkLabelLink *focus_link; - - if (!gtk_widget_is_focus (widget)) - { - gtk_widget_grab_focus (widget); - if (info) - { - focus_link = gtk_label_get_focus_link (self, NULL); - if (focus_link && direction == GTK_DIR_TAB_BACKWARD) - { - int i; - for (i = info->n_links - 1; i >= 0; i--) - { - focus_link = &info->links[i]; - if (!range_is_in_ellipsis (self, focus_link->start, focus_link->end)) - { - info->selection_anchor = focus_link->start; - info->selection_end = focus_link->start; - } - } - } - - return TRUE; - } - - return FALSE; - } - - if (!info) - return FALSE; - - if (info->selectable) - { - int index; - - if (info->selection_anchor != info->selection_end) - goto out; - - index = info->selection_anchor; - - if (direction == GTK_DIR_TAB_FORWARD) - { - guint i; - for (i = 0; i < info->n_links; i++) - { - const GtkLabelLink *link = &info->links[i]; - - if (link->start > index) - { - if (!range_is_in_ellipsis (self, link->start, link->end)) - { - gtk_label_select_region_index (self, link->start, link->start); - return TRUE; - } - } - } - } - else if (direction == GTK_DIR_TAB_BACKWARD) - { - int i; - for (i = info->n_links - 1; i >= 0; i--) - { - GtkLabelLink *link = &info->links[i]; - - if (link->end < index) - { - if (!range_is_in_ellipsis (self, link->start, link->end)) - { - gtk_label_select_region_index (self, link->start, link->start); - return TRUE; - } - } - } - } - - goto out; - } - else - { - int focus_link_index; - int new_index = -1; - int i; - - if (info->n_links == 0) - goto out; - - focus_link = gtk_label_get_focus_link (self, &focus_link_index); - - if (!focus_link) - goto out; - - switch (direction) - { - case GTK_DIR_TAB_FORWARD: - if (focus_link) - new_index = (focus_link_index + 1) % info->n_links; - else - new_index = 0; - - for (i = new_index; i < info->n_links; i++) - { - const GtkLabelLink *link = &info->links[i]; - if (!range_is_in_ellipsis (self, link->start, link->end)) - break; - } - break; - - case GTK_DIR_TAB_BACKWARD: - if (focus_link) - new_index = focus_link_index == 0 ? info->n_links - 1 : focus_link_index - 1; - else - new_index = info->n_links - 1; - - for (i = new_index; i >= 0; i--) - { - const GtkLabelLink *link = &info->links[i]; - if (!range_is_in_ellipsis (self, link->start, link->end)) - break; - } - break; - - default: - case GTK_DIR_UP: - case GTK_DIR_DOWN: - case GTK_DIR_LEFT: - case GTK_DIR_RIGHT: - goto out; - } - - if (new_index != -1) - { - focus_link = &info->links[new_index]; - info->selection_anchor = focus_link->start; - info->selection_end = focus_link->start; - gtk_widget_queue_draw (widget); - - return TRUE; - } - } - -out: - - return FALSE; -} - static void gtk_label_click_gesture_pressed (GtkGestureClick *gesture, int n_press, @@ -4139,7 +4293,7 @@ gtk_label_drag_gesture_update (GtkGestureDrag *gesture, if (info->in_drag) { if (gtk_drag_check_threshold (widget, info->drag_start_x, info->drag_start_y, x, y)) - { + { GdkDrag *drag; GdkSurface *surface; GdkDevice *device; @@ -4157,9 +4311,8 @@ gtk_label_drag_gesture_update (GtkGestureDrag *gesture, gtk_drag_icon_set_from_paintable (drag, get_selection_paintable (self), 0, 0); g_object_unref (drag); - - info->in_drag = FALSE; - } + info->in_drag = FALSE; + } } else { @@ -4212,6 +4365,34 @@ gtk_label_drag_gesture_update (GtkGestureDrag *gesture, } static void +gtk_label_update_actions (GtkLabel *self) +{ + GtkWidget *widget = GTK_WIDGET (self); + gboolean has_selection; + GtkLabelLink *link; + + if (self->select_info) + { + has_selection = self->select_info->selection_anchor != self->select_info->selection_end; + link = self->select_info->active_link; + } + else + { + has_selection = FALSE; + link = gtk_label_get_focus_link (self, NULL); + } + + gtk_widget_action_set_enabled (widget, "clipboard.cut", FALSE); + gtk_widget_action_set_enabled (widget, "clipboard.copy", has_selection); + gtk_widget_action_set_enabled (widget, "clipboard.paste", FALSE); + gtk_widget_action_set_enabled (widget, "selection.select-all", + gtk_label_get_selectable (self)); + gtk_widget_action_set_enabled (widget, "selection.delete", FALSE); + gtk_widget_action_set_enabled (widget, "link.open", !has_selection && link); + gtk_widget_action_set_enabled (widget, "link.copy", !has_selection && link); +} + +static void gtk_label_update_active_link (GtkWidget *widget, double x, double y) @@ -4530,9 +4711,9 @@ gtk_label_set_selectable (GtkLabel *self, /** * gtk_label_get_selectable: * @self: a #GtkLabel - * + * * Gets the value set by gtk_label_set_selectable(). - * + * * Returns: %TRUE if the user can copy text from the label **/ gboolean @@ -4678,10 +4859,10 @@ gtk_label_select_region (GtkLabel *self, { if (start_offset < 0) start_offset = g_utf8_strlen (self->text, -1); - + if (end_offset < 0) end_offset = g_utf8_strlen (self->text, -1); - + gtk_label_select_region_index (self, g_utf8_offset_to_pointer (self->text, start_offset) - self->text, g_utf8_offset_to_pointer (self->text, end_offset) - self->text); @@ -4693,10 +4874,10 @@ gtk_label_select_region (GtkLabel *self, * @self: a #GtkLabel * @start: (out): return location for start of selection, as a character offset * @end: (out): return location for end of selection, as a character offset - * + * * Gets the selected range of characters in the label, returning %TRUE * if there’s a selection. - * + * * Returns: %TRUE if selection is non-empty **/ gboolean @@ -4721,7 +4902,7 @@ gtk_label_get_selection_bounds (GtkLabel *self, int start_index, end_index; int start_offset, end_offset; int len; - + start_index = MIN (self->select_info->selection_anchor, self->select_info->selection_end); end_index = MAX (self->select_info->selection_anchor, @@ -4734,7 +4915,7 @@ gtk_label_get_selection_bounds (GtkLabel *self, if (start_index > len) start_index = len; - + start_offset = g_utf8_strlen (self->text, start_index); end_offset = g_utf8_strlen (self->text, end_index); @@ -4744,7 +4925,7 @@ gtk_label_get_selection_bounds (GtkLabel *self, start_offset = end_offset; end_offset = tmp; } - + if (start) *start = start_offset; @@ -4759,7 +4940,7 @@ gtk_label_get_selection_bounds (GtkLabel *self, /** * gtk_label_get_layout: * @self: a #GtkLabel - * + * * Gets the #PangoLayout used to display the label. * The layout is useful to e.g. convert text positions to * pixel positions, in combination with gtk_label_get_layout_offsets(). @@ -4989,11 +5170,10 @@ get_better_cursor (GtkLabel *self, static int gtk_label_move_logically (GtkLabel *self, - int start, - int count) + int start, + int count) { - int offset = g_utf8_pointer_to_offset (self->text, - self->text + start); + int offset = g_utf8_pointer_to_offset (self->text, self->text + start); if (self->text) { @@ -5008,21 +5188,21 @@ gtk_label_move_logically (GtkLabel *self, log_attrs = pango_layout_get_log_attrs_readonly (self->layout, &n_attrs); while (count > 0 && offset < length) - { - do - offset++; - while (offset < length && !log_attrs[offset].is_cursor_position); - - count--; - } + { + do + offset++; + while (offset < length && !log_attrs[offset].is_cursor_position); + + count--; + } while (count < 0 && offset > 0) - { - do - offset--; - while (offset > 0 && !log_attrs[offset].is_cursor_position); - - count++; - } + { + do + offset--; + while (offset > 0 && !log_attrs[offset].is_cursor_position); + + count++; + } } return g_utf8_offset_to_pointer (self->text, offset) - self->text; @@ -5030,13 +5210,13 @@ gtk_label_move_logically (GtkLabel *self, static int gtk_label_move_visually (GtkLabel *self, - int start, - int count) + int start, + int count) { int index; index = start; - + while (count != 0) { int new_index, new_trailing; @@ -5046,8 +5226,8 @@ gtk_label_move_visually (GtkLabel *self, gtk_label_ensure_layout (self); g_object_get (gtk_widget_get_settings (GTK_WIDGET (self)), - "gtk-split-cursor", &split_cursor, - NULL); + "gtk-split-cursor", &split_cursor, + NULL); if (split_cursor) strong = TRUE; @@ -5071,80 +5251,26 @@ gtk_label_move_visually (GtkLabel *self, } if (count > 0) - { - pango_layout_move_cursor_visually (self->layout, strong, index, 0, 1, &new_index, &new_trailing); - count--; - } + { + pango_layout_move_cursor_visually (self->layout, strong, index, 0, 1, &new_index, &new_trailing); + count--; + } else - { - pango_layout_move_cursor_visually (self->layout, strong, index, 0, -1, &new_index, &new_trailing); - count++; - } + { + pango_layout_move_cursor_visually (self->layout, strong, index, 0, -1, &new_index, &new_trailing); + count++; + } if (new_index < 0 || new_index == G_MAXINT) - break; + break; index = new_index; - - while (new_trailing--) - index = g_utf8_next_char (self->text + new_index) - self->text; - } - - return index; -} -static int -gtk_label_move_forward_word (GtkLabel *self, - int start) -{ - int new_pos = g_utf8_pointer_to_offset (self->text, - self->text + start); - int length; - - length = g_utf8_strlen (self->text, -1); - if (new_pos < length) - { - const PangoLogAttr *log_attrs; - int n_attrs; - - gtk_label_ensure_layout (self); - - log_attrs = pango_layout_get_log_attrs_readonly (self->layout, &n_attrs); - - /* Find the next word end */ - new_pos++; - while (new_pos < n_attrs && !log_attrs[new_pos].is_word_end) - new_pos++; - } - - return g_utf8_offset_to_pointer (self->text, new_pos) - self->text; -} - - -static int -gtk_label_move_backward_word (GtkLabel *self, - int start) -{ - int new_pos = g_utf8_pointer_to_offset (self->text, - self->text + start); - - if (new_pos > 0) - { - const PangoLogAttr *log_attrs; - int n_attrs; - - gtk_label_ensure_layout (self); - - log_attrs = pango_layout_get_log_attrs_readonly (self->layout, &n_attrs); - - new_pos -= 1; - - /* Find the previous word beginning */ - while (new_pos > 0 && !log_attrs[new_pos].is_word_start) - new_pos--; + while (new_trailing--) + index = g_utf8_next_char (self->text + new_index) - self->text; } - return g_utf8_offset_to_pointer (self->text, new_pos) - self->text; + return index; } static void @@ -5275,135 +5401,6 @@ gtk_label_move_cursor (GtkLabel *self, gtk_label_select_region_index (self, new_pos, new_pos); } -static void -gtk_label_copy_clipboard (GtkLabel *self) -{ - if (self->text && self->select_info) - { - int start, end; - int len; - GdkClipboard *clipboard; - - start = MIN (self->select_info->selection_anchor, - self->select_info->selection_end); - end = MAX (self->select_info->selection_anchor, - self->select_info->selection_end); - - len = strlen (self->text); - - if (end > len) - end = len; - - if (start > len) - start = len; - - clipboard = gtk_widget_get_clipboard (GTK_WIDGET (self)); - - if (start != end) - { - char *str = g_strndup (self->text + start, end - start); - gdk_clipboard_set_text (clipboard, str); - g_free (str); - } - else - { - GtkLabelLink *link; - - link = gtk_label_get_focus_link (self, NULL); - if (link) - gdk_clipboard_set_text (clipboard, link->uri); - } - } -} - -static void -gtk_label_select_all (GtkLabel *self) -{ - gtk_label_select_region_index (self, 0, strlen (self->text)); -} - -static void -gtk_label_activate_link_open (GtkWidget *widget, - const char *name, - GVariant *parameter) -{ - GtkLabel *self = GTK_LABEL (widget); - GtkLabelLink *link = self->select_info->context_link; - - if (link) - emit_activate_link (self, link); -} - -static void -gtk_label_activate_link_copy (GtkWidget *widget, - const char *name, - GVariant *parameter) -{ - GtkLabel *self = GTK_LABEL (widget); - GtkLabelLink *link = self->select_info->context_link; - - if (link) - { - GdkClipboard *clipboard; - - clipboard = gtk_widget_get_clipboard (widget); - gdk_clipboard_set_text (clipboard, link->uri); - } - else - g_print ("no link ?!\n"); -} - -static void -gtk_label_activate_clipboard_copy (GtkWidget *widget, - const char *name, - GVariant *parameter) -{ - g_signal_emit_by_name (widget, "copy-clipboard"); -} - -static void -gtk_label_activate_selection_select_all (GtkWidget *widget, - const char *name, - GVariant *parameter) -{ - gtk_label_select_all (GTK_LABEL (widget)); -} - -static void -gtk_label_nop (GtkWidget *widget, - const char *name, - GVariant *parameter) -{ -} - -static void -gtk_label_update_actions (GtkLabel *self) -{ - GtkWidget *widget = GTK_WIDGET (self); - gboolean has_selection; - GtkLabelLink *link; - - if (self->select_info) - { - has_selection = self->select_info->selection_anchor != self->select_info->selection_end; - link = self->select_info->active_link; - } - else - { - has_selection = FALSE; - link = gtk_label_get_focus_link (self, NULL); - } - - gtk_widget_action_set_enabled (widget, "clipboard.cut", FALSE); - gtk_widget_action_set_enabled (widget, "clipboard.copy", has_selection); - gtk_widget_action_set_enabled (widget, "clipboard.paste", FALSE); - gtk_widget_action_set_enabled (widget, "selection.select-all", - gtk_label_get_selectable (self)); - gtk_widget_action_set_enabled (widget, "selection.delete", FALSE); - gtk_widget_action_set_enabled (widget, "link.open", !has_selection && link); - gtk_widget_action_set_enabled (widget, "link.copy", !has_selection && link); -} - static GMenuModel * gtk_label_get_menu_model (GtkLabel *self) { @@ -5484,82 +5481,6 @@ gtk_label_do_popup (GtkLabel *self, gtk_popover_popup (GTK_POPOVER (self->popup_menu)); } -static void -gtk_label_popup_menu (GtkWidget *widget, - const char *action_name, - GVariant *parameters) -{ - GtkLabel *self = GTK_LABEL (widget); - - gtk_label_do_popup (self, -1, -1); -} - -static void -gtk_label_clear_links (GtkLabel *self) -{ - guint i; - - if (!self->select_info) - return; - - for (i = 0; i < self->select_info->n_links; i++) - link_free (&self->select_info->links[i]); - g_free (self->select_info->links); - self->select_info->links = NULL; - self->select_info->n_links = 0; - self->select_info->active_link = NULL; - gtk_widget_remove_css_class (GTK_WIDGET (self), "link"); -} - -static gboolean -gtk_label_activate_link (GtkLabel *self, - const char *uri) -{ - GtkWidget *widget = GTK_WIDGET (self); - GtkWidget *toplevel = GTK_WIDGET (gtk_widget_get_root (widget)); - - if (!GTK_IS_WINDOW (toplevel)) - return FALSE; - - gtk_show_uri (GTK_WINDOW (toplevel), uri, GDK_CURRENT_TIME); - - return TRUE; -} - -static void -emit_activate_link (GtkLabel *self, - GtkLabelLink *link) -{ - gboolean handled; - - g_signal_emit (self, signals[ACTIVATE_LINK], 0, link->uri, &handled); - - /* signal handler might have invalidated the layout */ - if (!self->layout) - return; - - if (handled && !link->visited && - self->select_info && self->select_info->links) - { - link->visited = TRUE; - update_link_state (self); - } -} - -static void -gtk_label_activate_current_link (GtkLabel *self) -{ - GtkLabelLink *link; - GtkWidget *widget = GTK_WIDGET (self); - - link = gtk_label_get_focus_link (self, NULL); - - if (link) - emit_activate_link (self, link); - else - gtk_widget_activate_default (widget); -} - /** * gtk_label_get_current_uri: * @self: a #GtkLabel @@ -5596,52 +5517,6 @@ gtk_label_get_current_uri (GtkLabel *self) return NULL; } -static gboolean -gtk_label_query_tooltip (GtkWidget *widget, - int x, - int y, - gboolean keyboard_tip, - GtkTooltip *tooltip) -{ - GtkLabel *self = GTK_LABEL (widget); - GtkLabelSelectionInfo *info = self->select_info; - int index = -1; - - if (info && info->links) - { - if (keyboard_tip) - { - if (info->selection_anchor == info->selection_end) - index = info->selection_anchor; - } - else - { - if (!get_layout_index (self, x, y, &index)) - index = -1; - } - - if (index != -1) - { - const int link_index = _gtk_label_get_link_at (self, index); - - if (link_index != -1) - { - const GtkLabelLink *link = &info->links[link_index]; - - if (link->title) - { - gtk_tooltip_set_markup (tooltip, link->title); - } - } - } - } - - return GTK_WIDGET_CLASS (gtk_label_parent_class)->query_tooltip (widget, - x, y, - keyboard_tip, - tooltip); -} - int _gtk_label_get_cursor_position (GtkLabel *self) { @@ -5704,111 +5579,6 @@ gtk_label_get_lines (GtkLabel *self) return self->lines; } -int -_gtk_label_get_n_links (GtkLabel *self) -{ - if (self->select_info) - return self->select_info->n_links; - - return 0; -} - -const char * -_gtk_label_get_link_uri (GtkLabel *self, - int idx) -{ - if (self->select_info) - return self->select_info->links[idx].uri; - - return NULL; -} - -void -_gtk_label_get_link_extent (GtkLabel *self, - int idx, - int *start, - int *end) -{ - if (self->select_info) - { - const GtkLabelLink *link = &self->select_info->links[idx]; - - *start = link->start; - *end = link->end; - } - else - { - *start = -1; - *end = -1; - } -} - -int -_gtk_label_get_link_at (GtkLabel *self, - int pos) -{ - if (self->select_info) - { - guint i; - - for (i = 0; i < self->select_info->n_links; i++) - { - const GtkLabelLink *link = &self->select_info->links[i]; - - if (link->start <= pos && pos < link->end) - return i; - } - } - - return -1; -} - -void -_gtk_label_activate_link (GtkLabel *self, - int idx) -{ - if (self->select_info) - { - GtkLabelLink *link = &self->select_info->links[idx]; - - emit_activate_link (self, link); - } -} - -gboolean -_gtk_label_get_link_visited (GtkLabel *self, - int idx) -{ - if (self->select_info) - return self->select_info->links[idx].visited; - - return FALSE; -} - -gboolean -_gtk_label_get_link_focused (GtkLabel *self, - int idx) -{ - GtkLabelSelectionInfo *info = self->select_info; - - if (!info) - return FALSE; - - if (info->selection_anchor != info->selection_end) - return FALSE; - - if (idx >= 0 && idx < info->n_links) - { - const GtkLabelLink *link = &info->links[idx]; - - if (link->start <= info->selection_anchor && - info->selection_anchor <= link->end) - return TRUE; - } - - return FALSE; -} - /** * gtk_label_set_xalign: * @self: a #GtkLabel @@ -5862,7 +5632,7 @@ gtk_label_set_yalign (GtkLabel *self, { g_return_if_fail (GTK_IS_LABEL (self)); - yalign = CLAMP (yalign, 0.0, 1.0); + yalign = CLAMP (yalign, 0.0, 1.0); if (self->yalign == yalign) return; diff --git a/gtk/gtklabelprivate.h b/gtk/gtklabelprivate.h index 3533949e86..5fbbf79cc3 100644 --- a/gtk/gtklabelprivate.h +++ b/gtk/gtklabelprivate.h @@ -24,27 +24,9 @@ G_BEGIN_DECLS -void _gtk_label_mnemonics_visible_apply_recursively (GtkWidget *widget, - gboolean mnemonics_visible); int _gtk_label_get_cursor_position (GtkLabel *label); int _gtk_label_get_selection_bound (GtkLabel *label); -int _gtk_label_get_n_links (GtkLabel *label); -int _gtk_label_get_link_at (GtkLabel *label, - int pos); -void _gtk_label_activate_link (GtkLabel *label, - int idx); -const char *_gtk_label_get_link_uri (GtkLabel *label, - int idx); -void _gtk_label_get_link_extent (GtkLabel *label, - int idx, - int *start, - int *end); -gboolean _gtk_label_get_link_visited (GtkLabel *label, - int idx); -gboolean _gtk_label_get_link_focused (GtkLabel *label, - int idx); - G_END_DECLS #endif /* __GTK_LABEL_PRIVATE_H__ */ diff --git a/gtk/gtkmessagedialog.c b/gtk/gtkmessagedialog.c index 171554d8cc..faa100354e 100644 --- a/gtk/gtkmessagedialog.c +++ b/gtk/gtkmessagedialog.c @@ -20,7 +20,7 @@ * Modified by the GTK+ Team and others 1997-2003. See the AUTHORS * file for a list of people on the GTK+ Team. See the ChangeLog * files for a list of changes. These files are distributed with - * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */ #include "config.h" @@ -113,18 +113,6 @@ struct _GtkMessageDialogClass GtkDialogClass parent_class; }; -static void gtk_message_dialog_constructed (GObject *object); -static void gtk_message_dialog_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); -static void gtk_message_dialog_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); -static void gtk_message_dialog_add_buttons (GtkMessageDialog *message_dialog, - GtkButtonsType buttons); - enum { PROP_0, PROP_MESSAGE_TYPE, @@ -140,147 +128,8 @@ enum { G_DEFINE_TYPE_WITH_PRIVATE (GtkMessageDialog, gtk_message_dialog, GTK_TYPE_DIALOG) static void -gtk_message_dialog_class_init (GtkMessageDialogClass *class) -{ - GtkWidgetClass *widget_class; - GObjectClass *gobject_class; - - widget_class = GTK_WIDGET_CLASS (class); - gobject_class = G_OBJECT_CLASS (class); - - gobject_class->constructed = gtk_message_dialog_constructed; - gobject_class->set_property = gtk_message_dialog_set_property; - gobject_class->get_property = gtk_message_dialog_get_property; - - /** - * GtkMessageDialog:message-type: - * - * The type of the message. - */ - g_object_class_install_property (gobject_class, - PROP_MESSAGE_TYPE, - g_param_spec_enum ("message-type", - P_("Message Type"), - P_("The type of message"), - GTK_TYPE_MESSAGE_TYPE, - GTK_MESSAGE_INFO, - GTK_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY)); - g_object_class_install_property (gobject_class, - PROP_BUTTONS, - g_param_spec_enum ("buttons", - P_("Message Buttons"), - P_("The buttons shown in the message dialog"), - GTK_TYPE_BUTTONS_TYPE, - GTK_BUTTONS_NONE, - GTK_PARAM_WRITABLE|G_PARAM_CONSTRUCT_ONLY)); - - /** - * GtkMessageDialog:text: - * - * The primary text of the message dialog. If the dialog has - * a secondary text, this will appear as the title. - */ - g_object_class_install_property (gobject_class, - PROP_TEXT, - g_param_spec_string ("text", - P_("Text"), - P_("The primary text of the message dialog"), - "", - GTK_PARAM_READWRITE)); - - /** - * GtkMessageDialog:use-markup: - * - * %TRUE if the primary text of the dialog includes Pango markup. - * See pango_parse_markup(). - */ - g_object_class_install_property (gobject_class, - PROP_USE_MARKUP, - g_param_spec_boolean ("use-markup", - P_("Use Markup"), - P_("The primary text of the title includes Pango markup."), - FALSE, - GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY)); - - /** - * GtkMessageDialog:secondary-text: - * - * The secondary text of the message dialog. - */ - g_object_class_install_property (gobject_class, - PROP_SECONDARY_TEXT, - g_param_spec_string ("secondary-text", - P_("Secondary Text"), - P_("The secondary text of the message dialog"), - NULL, - GTK_PARAM_READWRITE)); - - /** - * GtkMessageDialog:secondary-use-markup: - * - * %TRUE if the secondary text of the dialog includes Pango markup. - * See pango_parse_markup(). - */ - g_object_class_install_property (gobject_class, - PROP_SECONDARY_USE_MARKUP, - g_param_spec_boolean ("secondary-use-markup", - P_("Use Markup in secondary"), - P_("The secondary text includes Pango markup."), - FALSE, - GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY)); - - /** - * GtkMessageDialog:message-area: - * - * The #GtkBox that corresponds to the message area of this dialog. See - * gtk_message_dialog_get_message_area() for a detailed description of this - * area. - */ - g_object_class_install_property (gobject_class, - PROP_MESSAGE_AREA, - g_param_spec_object ("message-area", - P_("Message area"), - P_("GtkBox that holds the dialog’s primary and secondary labels"), - GTK_TYPE_WIDGET, - GTK_PARAM_READABLE)); - - /* Setup Composite data */ - gtk_widget_class_set_template_from_resource (widget_class, "/org/gtk/libgtk/ui/gtkmessagedialog.ui"); - gtk_widget_class_bind_template_child_private (widget_class, GtkMessageDialog, label); - gtk_widget_class_bind_template_child_private (widget_class, GtkMessageDialog, secondary_label); - gtk_widget_class_bind_template_child_internal_private (widget_class, GtkMessageDialog, message_area); -} - -static void -gtk_message_dialog_init (GtkMessageDialog *dialog) -{ - GtkMessageDialogPrivate *priv = gtk_message_dialog_get_instance_private (dialog); - GtkWidget *action_area; - GtkSettings *settings; - gboolean use_caret; - - priv->has_primary_markup = FALSE; - priv->has_secondary_text = FALSE; - priv->has_primary_markup = FALSE; - priv->has_secondary_text = FALSE; - priv->message_type = GTK_MESSAGE_OTHER; - - gtk_widget_add_css_class (GTK_WIDGET (dialog), "message"); - - gtk_widget_init_template (GTK_WIDGET (dialog)); - action_area = gtk_dialog_get_action_area (GTK_DIALOG (dialog)); - gtk_widget_set_halign (action_area, GTK_ALIGN_FILL); - gtk_box_set_homogeneous (GTK_BOX (action_area), TRUE); - - settings = gtk_widget_get_settings (GTK_WIDGET (dialog)); - g_object_get (settings, "gtk-keynav-use-caret", &use_caret, NULL); - gtk_label_set_selectable (GTK_LABEL (priv->label), use_caret); - gtk_label_set_selectable (GTK_LABEL (priv->secondary_label), use_caret); -} - -static void setup_type (GtkMessageDialog *dialog, - GtkMessageType type) + GtkMessageType type) { GtkMessageDialogPrivate *priv = gtk_message_dialog_get_instance_private (dialog); @@ -293,56 +142,52 @@ setup_type (GtkMessageDialog *dialog, } static void -update_title (GObject *dialog, - GParamSpec *pspec, - GtkWidget *label) +gtk_message_dialog_add_buttons (GtkMessageDialog *message_dialog, + GtkButtonsType buttons) { - const char *title; + GtkDialog* dialog = GTK_DIALOG (message_dialog); - title = gtk_window_get_title (GTK_WINDOW (dialog)); - gtk_label_set_label (GTK_LABEL (label), title); - gtk_widget_set_visible (label, title && title[0]); -} + switch (buttons) + { + case GTK_BUTTONS_NONE: + /* nothing */ + break; -static void -gtk_message_dialog_constructed (GObject *object) -{ - GtkMessageDialog *dialog = GTK_MESSAGE_DIALOG (object); - gboolean use_header; + case GTK_BUTTONS_OK: + gtk_dialog_add_button (dialog, _("_OK"), GTK_RESPONSE_OK); + break; - G_OBJECT_CLASS (gtk_message_dialog_parent_class)->constructed (object); + case GTK_BUTTONS_CLOSE: + gtk_dialog_add_button (dialog, _("_Close"), GTK_RESPONSE_CLOSE); + break; - g_object_get (gtk_widget_get_settings (GTK_WIDGET (dialog)), - "gtk-dialogs-use-header", &use_header, - NULL); + case GTK_BUTTONS_CANCEL: + gtk_dialog_add_button (dialog, _("_Cancel"), GTK_RESPONSE_CANCEL); + break; - if (use_header) - { - GtkWidget *box; - GtkWidget *label; + case GTK_BUTTONS_YES_NO: + gtk_dialog_add_button (dialog, _("_No"), GTK_RESPONSE_NO); + gtk_dialog_add_button (dialog, _("_Yes"), GTK_RESPONSE_YES); + break; - box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); - gtk_widget_show (box); - gtk_widget_set_size_request (box, -1, 16); - label = gtk_label_new (""); - gtk_widget_hide (label); - gtk_widget_set_margin_top (label, 6); - gtk_widget_set_margin_bottom (label, 6); - gtk_widget_set_halign (label, GTK_ALIGN_CENTER); - gtk_widget_set_hexpand (label, TRUE); - gtk_widget_add_css_class (label, "title"); - gtk_box_append (GTK_BOX (box), label); - g_signal_connect_object (dialog, "notify::title", G_CALLBACK (update_title), label, 0); + case GTK_BUTTONS_OK_CANCEL: + gtk_dialog_add_button (dialog, _("_Cancel"), GTK_RESPONSE_CANCEL); + gtk_dialog_add_button (dialog, _("_OK"), GTK_RESPONSE_OK); + break; - gtk_window_set_titlebar (GTK_WINDOW (dialog), box); + default: + g_warning ("Unknown GtkButtonsType"); + break; } + + g_object_notify (G_OBJECT (message_dialog), "buttons"); } -static void +static void gtk_message_dialog_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) + guint prop_id, + const GValue *value, + GParamSpec *pspec) { GtkMessageDialog *dialog = GTK_MESSAGE_DIALOG (object); GtkMessageDialogPrivate *priv = gtk_message_dialog_get_instance_private (dialog); @@ -357,11 +202,9 @@ gtk_message_dialog_set_property (GObject *object, break; case PROP_TEXT: if (priv->has_primary_markup) - gtk_label_set_markup (GTK_LABEL (priv->label), - g_value_get_string (value)); + gtk_label_set_markup (GTK_LABEL (priv->label), g_value_get_string (value)); else - gtk_label_set_text (GTK_LABEL (priv->label), - g_value_get_string (value)); + gtk_label_set_text (GTK_LABEL (priv->label), g_value_get_string (value)); break; case PROP_USE_MARKUP: if (priv->has_primary_markup != g_value_get_boolean (value)) @@ -373,25 +216,25 @@ gtk_message_dialog_set_property (GObject *object, break; case PROP_SECONDARY_TEXT: { - const char *txt = g_value_get_string (value); - - if (gtk_label_get_use_markup (GTK_LABEL (priv->secondary_label))) - gtk_label_set_markup (GTK_LABEL (priv->secondary_label), txt); - else - gtk_label_set_text (GTK_LABEL (priv->secondary_label), txt); - - if (txt) - { - priv->has_secondary_text = TRUE; - gtk_widget_add_css_class (priv->label, "title"); - gtk_widget_show (priv->secondary_label); - } - else - { - priv->has_secondary_text = FALSE; - gtk_widget_remove_css_class (priv->label, "title"); - gtk_widget_hide (priv->secondary_label); - } + const char *txt = g_value_get_string (value); + + if (gtk_label_get_use_markup (GTK_LABEL (priv->secondary_label))) + gtk_label_set_markup (GTK_LABEL (priv->secondary_label), txt); + else + gtk_label_set_text (GTK_LABEL (priv->secondary_label), txt); + + if (txt) + { + priv->has_secondary_text = TRUE; + gtk_widget_add_css_class (priv->label, "title"); + gtk_widget_show (priv->secondary_label); + } + else + { + priv->has_secondary_text = FALSE; + gtk_widget_remove_css_class (priv->label, "title"); + gtk_widget_hide (priv->secondary_label); + } } break; case PROP_SECONDARY_USE_MARKUP: @@ -408,11 +251,11 @@ gtk_message_dialog_set_property (GObject *object, } } -static void +static void gtk_message_dialog_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) + guint prop_id, + GValue *value, + GParamSpec *pspec) { GtkMessageDialog *dialog = GTK_MESSAGE_DIALOG (object); GtkMessageDialogPrivate *priv = gtk_message_dialog_get_instance_private (dialog); @@ -430,17 +273,17 @@ gtk_message_dialog_get_property (GObject *object, break; case PROP_SECONDARY_TEXT: if (priv->has_secondary_text) - g_value_set_string (value, - gtk_label_get_label (GTK_LABEL (priv->secondary_label))); + g_value_set_string (value, + gtk_label_get_label (GTK_LABEL (priv->secondary_label))); else - g_value_set_string (value, NULL); + g_value_set_string (value, NULL); break; case PROP_SECONDARY_USE_MARKUP: if (priv->has_secondary_text) - g_value_set_boolean (value, - gtk_label_get_use_markup (GTK_LABEL (priv->secondary_label))); + g_value_set_boolean (value, + gtk_label_get_use_markup (GTK_LABEL (priv->secondary_label))); else - g_value_set_boolean (value, FALSE); + g_value_set_boolean (value, FALSE); break; case PROP_MESSAGE_AREA: g_value_set_object (value, priv->message_area); @@ -451,6 +294,185 @@ gtk_message_dialog_get_property (GObject *object, } } +static void +update_title (GObject *dialog, + GParamSpec *pspec, + GtkWidget *label) +{ + const char *title; + + title = gtk_window_get_title (GTK_WINDOW (dialog)); + gtk_label_set_label (GTK_LABEL (label), title); + gtk_widget_set_visible (label, title && title[0]); +} + +static void +gtk_message_dialog_constructed (GObject *object) +{ + GtkMessageDialog *dialog = GTK_MESSAGE_DIALOG (object); + gboolean use_header; + + G_OBJECT_CLASS (gtk_message_dialog_parent_class)->constructed (object); + + g_object_get (gtk_widget_get_settings (GTK_WIDGET (dialog)), + "gtk-dialogs-use-header", &use_header, + NULL); + + if (use_header) + { + GtkWidget *box; + GtkWidget *label; + + box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + gtk_widget_show (box); + gtk_widget_set_size_request (box, -1, 16); + label = gtk_label_new (""); + gtk_widget_hide (label); + gtk_widget_set_margin_top (label, 6); + gtk_widget_set_margin_bottom (label, 6); + gtk_widget_set_halign (label, GTK_ALIGN_CENTER); + gtk_widget_set_hexpand (label, TRUE); + gtk_widget_add_css_class (label, "title"); + gtk_box_append (GTK_BOX (box), label); + g_signal_connect_object (dialog, "notify::title", G_CALLBACK (update_title), label, 0); + + gtk_window_set_titlebar (GTK_WINDOW (dialog), box); + } +} + +static void +gtk_message_dialog_class_init (GtkMessageDialogClass *class) +{ + GtkWidgetClass *widget_class; + GObjectClass *gobject_class; + + widget_class = GTK_WIDGET_CLASS (class); + gobject_class = G_OBJECT_CLASS (class); + + gobject_class->constructed = gtk_message_dialog_constructed; + gobject_class->set_property = gtk_message_dialog_set_property; + gobject_class->get_property = gtk_message_dialog_get_property; + + /** + * GtkMessageDialog:message-type: + * + * The type of the message. + */ + g_object_class_install_property (gobject_class, + PROP_MESSAGE_TYPE, + g_param_spec_enum ("message-type", + P_("Message Type"), + P_("The type of message"), + GTK_TYPE_MESSAGE_TYPE, + GTK_MESSAGE_INFO, + GTK_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY)); + g_object_class_install_property (gobject_class, + PROP_BUTTONS, + g_param_spec_enum ("buttons", + P_("Message Buttons"), + P_("The buttons shown in the message dialog"), + GTK_TYPE_BUTTONS_TYPE, + GTK_BUTTONS_NONE, + GTK_PARAM_WRITABLE|G_PARAM_CONSTRUCT_ONLY)); + /** + * GtkMessageDialog:text: + * + * The primary text of the message dialog. If the dialog has + * a secondary text, this will appear as the title. + */ + g_object_class_install_property (gobject_class, + PROP_TEXT, + g_param_spec_string ("text", + P_("Text"), + P_("The primary text of the message dialog"), + "", + GTK_PARAM_READWRITE)); + /** + * GtkMessageDialog:use-markup: + * + * %TRUE if the primary text of the dialog includes Pango markup. + * See pango_parse_markup(). + */ + g_object_class_install_property (gobject_class, + PROP_USE_MARKUP, + g_param_spec_boolean ("use-markup", + P_("Use Markup"), + P_("The primary text of the title includes Pango markup."), + FALSE, + GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY)); + /** + * GtkMessageDialog:secondary-text: + * + * The secondary text of the message dialog. + */ + g_object_class_install_property (gobject_class, + PROP_SECONDARY_TEXT, + g_param_spec_string ("secondary-text", + P_("Secondary Text"), + P_("The secondary text of the message dialog"), + NULL, + GTK_PARAM_READWRITE)); + /** + * GtkMessageDialog:secondary-use-markup: + * + * %TRUE if the secondary text of the dialog includes Pango markup. + * See pango_parse_markup(). + */ + g_object_class_install_property (gobject_class, + PROP_SECONDARY_USE_MARKUP, + g_param_spec_boolean ("secondary-use-markup", + P_("Use Markup in secondary"), + P_("The secondary text includes Pango markup."), + FALSE, + GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY)); + /** + * GtkMessageDialog:message-area: + * + * The #GtkBox that corresponds to the message area of this dialog. See + * gtk_message_dialog_get_message_area() for a detailed description of this + * area. + */ + g_object_class_install_property (gobject_class, + PROP_MESSAGE_AREA, + g_param_spec_object ("message-area", + P_("Message area"), + P_("GtkBox that holds the dialog’s primary and secondary labels"), + GTK_TYPE_WIDGET, + GTK_PARAM_READABLE)); + + gtk_widget_class_set_template_from_resource (widget_class, "/org/gtk/libgtk/ui/gtkmessagedialog.ui"); + gtk_widget_class_bind_template_child_private (widget_class, GtkMessageDialog, label); + gtk_widget_class_bind_template_child_private (widget_class, GtkMessageDialog, secondary_label); + gtk_widget_class_bind_template_child_internal_private (widget_class, GtkMessageDialog, message_area); +} + +static void +gtk_message_dialog_init (GtkMessageDialog *dialog) +{ + GtkMessageDialogPrivate *priv = gtk_message_dialog_get_instance_private (dialog); + GtkWidget *action_area; + GtkSettings *settings; + gboolean use_caret; + + priv->has_primary_markup = FALSE; + priv->has_secondary_text = FALSE; + priv->has_primary_markup = FALSE; + priv->has_secondary_text = FALSE; + priv->message_type = GTK_MESSAGE_OTHER; + + gtk_widget_add_css_class (GTK_WIDGET (dialog), "message"); + + gtk_widget_init_template (GTK_WIDGET (dialog)); + action_area = gtk_dialog_get_action_area (GTK_DIALOG (dialog)); + gtk_widget_set_halign (action_area, GTK_ALIGN_FILL); + gtk_box_set_homogeneous (GTK_BOX (action_area), TRUE); + + settings = gtk_widget_get_settings (GTK_WIDGET (dialog)); + g_object_get (settings, "gtk-keynav-use-caret", &use_caret, NULL); + gtk_label_set_selectable (GTK_LABEL (priv->label), use_caret); + gtk_label_set_selectable (GTK_LABEL (priv->secondary_label), use_caret); +} + /** * gtk_message_dialog_new: * @parent: (allow-none): transient parent, or %NULL for none @@ -484,9 +506,9 @@ gtk_message_dialog_new (GtkWindow *parent, widget = g_object_new (GTK_TYPE_MESSAGE_DIALOG, "use-header-bar", FALSE, - "message-type", type, - "buttons", buttons, - NULL); + "message-type", type, + "buttons", buttons, + NULL); dialog = GTK_DIALOG (widget); if (message_format) @@ -547,7 +569,7 @@ gtk_message_dialog_new (GtkWindow *parent, * gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dialog), * markup); * ]| - * + * * Returns: a new #GtkMessageDialog **/ GtkWidget* @@ -584,7 +606,7 @@ gtk_message_dialog_new_with_markup (GtkWindow *parent, * gtk_message_dialog_set_markup: * @message_dialog: a #GtkMessageDialog * @str: markup string (see [Pango markup format][PangoMarkupFormat]) - * + * * Sets the text of the message dialog to be @str, which is marked * up with the [Pango text markup language][PangoMarkupFormat]. **/ @@ -723,45 +745,3 @@ gtk_message_dialog_get_message_area (GtkMessageDialog *message_dialog) return priv->message_area; } -static void -gtk_message_dialog_add_buttons (GtkMessageDialog* message_dialog, - GtkButtonsType buttons) -{ - GtkDialog* dialog = GTK_DIALOG (message_dialog); - - switch (buttons) - { - case GTK_BUTTONS_NONE: - /* nothing */ - break; - - case GTK_BUTTONS_OK: - gtk_dialog_add_button (dialog, _("_OK"), GTK_RESPONSE_OK); - break; - - case GTK_BUTTONS_CLOSE: - gtk_dialog_add_button (dialog, _("_Close"), GTK_RESPONSE_CLOSE); - break; - - case GTK_BUTTONS_CANCEL: - gtk_dialog_add_button (dialog, _("_Cancel"), GTK_RESPONSE_CANCEL); - break; - - case GTK_BUTTONS_YES_NO: - gtk_dialog_add_button (dialog, _("_No"), GTK_RESPONSE_NO); - gtk_dialog_add_button (dialog, _("_Yes"), GTK_RESPONSE_YES); - break; - - case GTK_BUTTONS_OK_CANCEL: - gtk_dialog_add_button (dialog, _("_Cancel"), GTK_RESPONSE_CANCEL); - gtk_dialog_add_button (dialog, _("_OK"), GTK_RESPONSE_OK); - break; - - default: - g_warning ("Unknown GtkButtonsType"); - break; - } - - g_object_notify (G_OBJECT (message_dialog), "buttons"); -} - diff --git a/gtk/gtkrender.c b/gtk/gtkrender.c index a094604d7a..1a18290353 100644 --- a/gtk/gtkrender.c +++ b/gtk/gtkrender.c @@ -368,32 +368,6 @@ gtk_render_layout (GtkStyleContext *context, gsk_render_node_unref (node); } -static void -gtk_do_render_line (GtkStyleContext *context, - cairo_t *cr, - double x0, - double y0, - double x1, - double y1) -{ - const GdkRGBA *color; - - cairo_save (cr); - - color = gtk_css_color_value_get_rgba (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_COLOR)); - - cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE); - cairo_set_line_width (cr, 1); - - cairo_move_to (cr, x0 + 0.5, y0 + 0.5); - cairo_line_to (cr, x1 + 0.5, y1 + 0.5); - - gdk_cairo_set_source_rgba (cr, color); - cairo_stroke (cr); - - cairo_restore (cr); -} - /** * gtk_render_line: * @context: a #GtkStyleContext @@ -413,10 +387,25 @@ gtk_render_line (GtkStyleContext *context, double x1, double y1) { + const GdkRGBA *color; + g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (cr != NULL); - gtk_do_render_line (context, cr, x0, y0, x1, y1); + cairo_save (cr); + + color = gtk_css_color_value_get_rgba (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_COLOR)); + + cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE); + cairo_set_line_width (cr, 1); + + cairo_move_to (cr, x0 + 0.5, y0 + 0.5); + cairo_line_to (cr, x1 + 0.5, y1 + 0.5); + + gdk_cairo_set_source_rgba (cr, color); + cairo_stroke (cr); + + cairo_restore (cr); } /** diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c index d27d05c432..53136833c8 100644 --- a/gtk/gtkscrolledwindow.c +++ b/gtk/gtkscrolledwindow.c @@ -1087,11 +1087,7 @@ static void indicator_set_over (Indicator *indicator, gboolean over) { - if (indicator->over_timeout_id) - { - g_source_remove (indicator->over_timeout_id); - indicator->over_timeout_id = 0; - } + g_clear_handle_id (&indicator->over_timeout_id, g_source_remove); if (indicator->over == over) return; @@ -1170,11 +1166,8 @@ check_update_scrollbar_proximity (GtkScrolledWindow *sw, gtk_widget_is_ancestor (target, priv->hindicator.scrollbar) || gtk_widget_is_ancestor (target, priv->vindicator.scrollbar))); - if (indicator->over_timeout_id) - { - g_source_remove (indicator->over_timeout_id); - indicator->over_timeout_id = 0; - } + + g_clear_handle_id (&indicator->over_timeout_id, g_source_remove); if (on_scrollbar) indicator_set_over (indicator, TRUE); @@ -1374,11 +1367,7 @@ scrolled_window_scroll (GtkScrolledWindow *scrolled_window, new_value); } - if (priv->scroll_events_overshoot_id) - { - g_source_remove (priv->scroll_events_overshoot_id); - priv->scroll_events_overshoot_id = 0; - } + g_clear_handle_id (&priv->scroll_events_overshoot_id, g_source_remove); if (!priv->smooth_scroll && _gtk_scrolled_window_get_overshoot (scrolled_window, NULL, NULL)) @@ -2610,12 +2599,7 @@ gtk_scrolled_window_dispose (GObject *object) g_clear_pointer (&priv->hscrolling, gtk_kinetic_scrolling_free); g_clear_pointer (&priv->vscrolling, gtk_kinetic_scrolling_free); - - if (priv->scroll_events_overshoot_id) - { - g_source_remove (priv->scroll_events_overshoot_id); - priv->scroll_events_overshoot_id = 0; - } + g_clear_handle_id (&priv->scroll_events_overshoot_id, g_source_remove); G_OBJECT_CLASS (gtk_scrolled_window_parent_class)->dispose (object); } @@ -3547,17 +3531,8 @@ gtk_scrolled_window_map (GtkWidget *widget) static void indicator_reset (Indicator *indicator) { - if (indicator->conceil_timer) - { - g_source_remove (indicator->conceil_timer); - indicator->conceil_timer = 0; - } - - if (indicator->over_timeout_id) - { - g_source_remove (indicator->over_timeout_id); - indicator->over_timeout_id = 0; - } + g_clear_handle_id (&indicator->conceil_timer, g_source_remove); + g_clear_handle_id (&indicator->over_timeout_id, g_source_remove); if (indicator->scrollbar && indicator->tick_id) { diff --git a/gtk/gtksettings.c b/gtk/gtksettings.c index 595e7a1810..2338fcf530 100644 --- a/gtk/gtksettings.c +++ b/gtk/gtksettings.c @@ -95,11 +95,6 @@ * to use gtk_widget_get_settings(). */ - -#define DEFAULT_TIMEOUT_INITIAL 500 -#define DEFAULT_TIMEOUT_REPEAT 50 -#define DEFAULT_TIMEOUT_EXPAND 500 - typedef struct _GtkSettingsClass GtkSettingsClass; typedef struct _GtkSettingsPropertyValue GtkSettingsPropertyValue; typedef struct _GtkSettingsValuePrivate GtkSettingsValuePrivate; @@ -241,6 +236,7 @@ static void gtk_settings_init (GtkSettings *settings) { GParamSpec **pspecs, **p; + guint n_pspecs; guint i = 0; char *path; const char * const *config_dirs; @@ -255,14 +251,11 @@ gtk_settings_init (GtkSettings *settings) * notification for them (at least notification for internal properties * will instantly be caught) */ - pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (settings), NULL); - for (p = pspecs; *p; p++) - if ((*p)->owner_type == G_OBJECT_TYPE (settings)) - i++; - settings->property_values = g_new0 (GtkSettingsPropertyValue, i); - i = 0; + pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (settings), &n_pspecs); + settings->property_values = g_new0 (GtkSettingsPropertyValue, n_pspecs); g_object_freeze_notify (G_OBJECT (settings)); + i = 0; for (p = pspecs; *p; p++) { GParamSpec *pspec = *p; @@ -280,27 +273,23 @@ gtk_settings_init (GtkSettings *settings) g_free (pspecs); path = g_build_filename (_gtk_get_data_prefix (), "share", "gtk-4.0", "settings.ini", NULL); - if (g_file_test (path, G_FILE_TEST_EXISTS)) - gtk_settings_load_from_key_file (settings, path, GTK_SETTINGS_SOURCE_DEFAULT); + gtk_settings_load_from_key_file (settings, path, GTK_SETTINGS_SOURCE_DEFAULT); g_free (path); path = g_build_filename (_gtk_get_sysconfdir (), "gtk-4.0", "settings.ini", NULL); - if (g_file_test (path, G_FILE_TEST_EXISTS)) - gtk_settings_load_from_key_file (settings, path, GTK_SETTINGS_SOURCE_DEFAULT); + gtk_settings_load_from_key_file (settings, path, GTK_SETTINGS_SOURCE_DEFAULT); g_free (path); config_dirs = g_get_system_config_dirs (); for (i = 0; config_dirs[i] != NULL; i++) { path = g_build_filename (config_dirs[i], "gtk-4.0", "settings.ini", NULL); - if (g_file_test (path, G_FILE_TEST_EXISTS)) - gtk_settings_load_from_key_file (settings, path, GTK_SETTINGS_SOURCE_DEFAULT); + gtk_settings_load_from_key_file (settings, path, GTK_SETTINGS_SOURCE_DEFAULT); g_free (path); } path = g_build_filename (g_get_user_config_dir (), "gtk-4.0", "settings.ini", NULL); - if (g_file_test (path, G_FILE_TEST_EXISTS)) - gtk_settings_load_from_key_file (settings, path, GTK_SETTINGS_SOURCE_DEFAULT); + gtk_settings_load_from_key_file (settings, path, GTK_SETTINGS_SOURCE_DEFAULT); g_free (path); g_object_thaw_notify (G_OBJECT (settings)); @@ -1695,8 +1684,7 @@ settings_update_theme (GtkSettings *settings) if (theme_dir) { path = g_build_filename (theme_dir, "settings.ini", NULL); - if (g_file_test (path, G_FILE_TEST_EXISTS)) - gtk_settings_load_from_key_file (settings, path, GTK_SETTINGS_SOURCE_THEME); + gtk_settings_load_from_key_file (settings, path, GTK_SETTINGS_SOURCE_THEME); g_free (path); } @@ -1733,13 +1721,18 @@ gtk_settings_load_from_key_file (GtkSettings *settings, char **keys; gsize n_keys; int i; + char *contents; + gsize contents_len; + + if (!g_file_get_contents (path, &contents, &contents_len, NULL)) + return; error = NULL; keys = NULL; keyfile = g_key_file_new (); - if (!g_key_file_load_from_file (keyfile, path, G_KEY_FILE_NONE, &error)) + if (!g_key_file_load_from_data (keyfile, contents, contents_len, G_KEY_FILE_NONE, &error)) { g_warning ("Failed to parse %s: %s", path, error->message); @@ -1850,6 +1843,7 @@ gtk_settings_load_from_key_file (GtkSettings *settings, } out: + g_free (contents); g_strfreev (keys); g_key_file_free (keyfile); } diff --git a/gtk/gtkshortcutmanager.c b/gtk/gtkshortcutmanager.c index 0351490df2..ec70791e77 100644 --- a/gtk/gtkshortcutmanager.c +++ b/gtk/gtkshortcutmanager.c @@ -108,24 +108,11 @@ gtk_shortcut_manager_default_remove_controller (GtkShortcutManager *self, if (model) { GListModel *store; - guint position, len; + guint position; store = gtk_flatten_list_model_get_model (model); -#if 0 && GLIB_CHECK_VERSION(2,64,0) - if (_g_list_store_find (G_LIST_STORE (store), controller, &position)) + if (g_list_store_find (G_LIST_STORE (store), controller, &position)) g_list_store_remove (G_LIST_STORE (store), position); -#else - for (position = 0, len = g_list_model_get_n_items (store); position < len; position++) - { - GtkShortcutController *item = g_list_model_get_item (store, position); - g_object_unref (item); - if (item == controller) - { - g_list_store_remove (G_LIST_STORE (store), position); - break; - } - } -#endif } } diff --git a/gtk/gtkshortcuttrigger.c b/gtk/gtkshortcuttrigger.c index 46e2f9cc96..fab339fe54 100644 --- a/gtk/gtkshortcuttrigger.c +++ b/gtk/gtkshortcuttrigger.c @@ -399,9 +399,6 @@ gtk_shortcut_trigger_compare (gconstpointer trigger1, struct _GtkNeverTrigger { GtkShortcutTrigger parent_instance; - - guint never; - GdkModifierType modifiers; }; struct _GtkNeverTriggerClass diff --git a/gtk/gtkviewport.c b/gtk/gtkviewport.c index 42bf850864..0581a95e9d 100644 --- a/gtk/gtkviewport.c +++ b/gtk/gtkviewport.c @@ -71,7 +71,7 @@ struct _GtkViewport GtkAdjustment *hadjustment; GtkAdjustment *vadjustment; - + /* GtkScrollablePolicy needs to be checked when * driving the scrollable adjustment values */ guint hscroll_policy : 1; @@ -244,9 +244,7 @@ gtk_viewport_measure (GtkWidget *widget, { GtkViewport *viewport = GTK_VIEWPORT (widget); - *minimum = *natural = 0; - - if (viewport->child && gtk_widget_get_visible (viewport->child)) + if (viewport->child) gtk_widget_measure (viewport->child, orientation, for_size, diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index b26103e87b..239f7735e8 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -8,7 +8,7 @@ * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public @@ -452,16 +452,11 @@ GTK_STATE_FLAG_ACTIVE) typedef struct { - char *name; /* Name of the template automatic child */ - gboolean internal_child; /* Whether the automatic widget should be exported as an <internal-child> */ - gssize offset; /* Instance private data offset where to set the automatic child (or 0) */ + char *name; /* Name of the template automatic child */ + gboolean internal_child; /* Whether the automatic widget should be exported as an <internal-child> */ + gssize offset; /* Instance private data offset where to set the automatic child (or 0) */ } AutomaticChildClass; -typedef struct { - char *callback_name; - GCallback callback_symbol; -} CallbackSymbol; - enum { DESTROY, SHOW, @@ -521,97 +516,64 @@ enum { PROP_ACCESSIBLE_ROLE }; -static GParamSpec *widget_props[NUM_PROPERTIES] = { NULL, }; -typedef struct _GtkStateData GtkStateData; - -struct _GtkStateData +typedef struct { guint flags_to_set; guint flags_to_unset; int old_scale_factor; -}; - -/* --- prototypes --- */ -static void gtk_widget_base_class_init (gpointer g_class); -static void gtk_widget_class_init (GtkWidgetClass *klass); -static void gtk_widget_base_class_finalize (GtkWidgetClass *klass); -static void gtk_widget_init (GTypeInstance *instance, - gpointer g_class); -static void gtk_widget_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); -static void gtk_widget_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); -static void gtk_widget_dispose (GObject *object); -static void gtk_widget_finalize (GObject *object); -static void gtk_widget_real_destroy (GtkWidget *object); -static gboolean gtk_widget_real_focus (GtkWidget *widget, - GtkDirectionType direction); -static void gtk_widget_real_show (GtkWidget *widget); -static void gtk_widget_real_hide (GtkWidget *widget); -static void gtk_widget_real_map (GtkWidget *widget); -static void gtk_widget_real_unmap (GtkWidget *widget); -static void gtk_widget_real_realize (GtkWidget *widget); -static void gtk_widget_real_unrealize (GtkWidget *widget); -static void gtk_widget_real_size_allocate (GtkWidget *widget, - int width, - int height, - int baseline); -static void gtk_widget_real_direction_changed(GtkWidget *widget, - GtkTextDirection previous_direction); - -static gboolean gtk_widget_real_query_tooltip (GtkWidget *widget, - int x, - int y, - gboolean keyboard_tip, - GtkTooltip *tooltip); -static void gtk_widget_real_css_changed (GtkWidget *widget, - GtkCssStyleChange *change); -static void gtk_widget_real_system_setting_changed (GtkWidget *widget, - GtkSystemSetting setting); - -static void gtk_widget_real_set_focus_child (GtkWidget *widget, - GtkWidget *child); -static void gtk_widget_real_move_focus (GtkWidget *widget, - GtkDirectionType direction); -static gboolean gtk_widget_real_keynav_failed (GtkWidget *widget, - GtkDirectionType direction); +} GtkStateData; + + +static void gtk_widget_base_class_init (gpointer g_class); +static void gtk_widget_class_init (GtkWidgetClass *klass); +static void gtk_widget_base_class_finalize (GtkWidgetClass *klass); +static void gtk_widget_init (GTypeInstance *instance, + gpointer g_class); +static void gtk_widget_dispose (GObject *object); +static void gtk_widget_finalize (GObject *object); +static void gtk_widget_real_destroy (GtkWidget *object); +static gboolean gtk_widget_real_focus (GtkWidget *widget, + GtkDirectionType direction); +static void gtk_widget_real_show (GtkWidget *widget); +static void gtk_widget_real_hide (GtkWidget *widget); +static void gtk_widget_real_map (GtkWidget *widget); +static void gtk_widget_real_unmap (GtkWidget *widget); +static void gtk_widget_real_realize (GtkWidget *widget); +static void gtk_widget_real_unrealize (GtkWidget *widget); +static void gtk_widget_real_direction_changed (GtkWidget *widget, + GtkTextDirection previous_direction); +static void gtk_widget_real_css_changed (GtkWidget *widget, + GtkCssStyleChange *change); +static void gtk_widget_real_system_setting_changed (GtkWidget *widget, + GtkSystemSetting setting); +static void gtk_widget_real_set_focus_child (GtkWidget *widget, + GtkWidget *child); +static void gtk_widget_real_move_focus (GtkWidget *widget, + GtkDirectionType direction); +static gboolean gtk_widget_real_keynav_failed (GtkWidget *widget, + GtkDirectionType direction); #ifdef G_ENABLE_CONSISTENCY_CHECKS -static void gtk_widget_verify_invariants (GtkWidget *widget); -static void gtk_widget_push_verify_invariants (GtkWidget *widget); -static void gtk_widget_pop_verify_invariants (GtkWidget *widget); +static void gtk_widget_verify_invariants (GtkWidget *widget); +static void gtk_widget_push_verify_invariants (GtkWidget *widget); +static void gtk_widget_pop_verify_invariants (GtkWidget *widget); #else #define gtk_widget_verify_invariants(widget) #define gtk_widget_push_verify_invariants(widget) #define gtk_widget_pop_verify_invariants(widget) #endif -static PangoContext* gtk_widget_peek_pango_context (GtkWidget *widget); -static void gtk_widget_update_pango_context (GtkWidget *widget); +static PangoContext* gtk_widget_peek_pango_context (GtkWidget *widget); +static void gtk_widget_update_pango_context (GtkWidget *widget); static void gtk_widget_propagate_state (GtkWidget *widget, const GtkStateData *data); -static gboolean gtk_widget_real_mnemonic_activate (GtkWidget *widget, - gboolean group_cycling); -static void gtk_widget_real_measure (GtkWidget *widget, - GtkOrientation orientation, - int for_size, - int *minimum, - int *natural, - int *minimum_baseline, - int *natural_baseline); -static void gtk_widget_real_state_flags_changed (GtkWidget *widget, - GtkStateFlags old_state); - +static gboolean gtk_widget_real_mnemonic_activate (GtkWidget *widget, + gboolean group_cycling); static void gtk_widget_accessible_interface_init (GtkAccessibleInterface *iface); - static void gtk_widget_buildable_interface_init (GtkBuildableIface *iface); static void gtk_widget_buildable_set_id (GtkBuildable *buildable, const char *id); -static const char * gtk_widget_buildable_get_id (GtkBuildable *buildable); +static const char * gtk_widget_buildable_get_id (GtkBuildable *buildable); static GObject * gtk_widget_buildable_get_internal_child (GtkBuildable *buildable, GtkBuilder *builder, const char *childname); @@ -633,44 +595,31 @@ static void gtk_widget_buildable_custom_finished (GtkBuildable gpointer data); static void gtk_widget_buildable_parser_finished (GtkBuildable *buildable, GtkBuilder *builder); +static void gtk_widget_set_usize_internal (GtkWidget *widget, + int width, + int height); -static void gtk_widget_set_accessible_role (GtkWidget *self, - GtkAccessibleRole role); -static GtkAccessibleRole gtk_widget_get_accessible_role (GtkWidget *self); - -static GtkSizeRequestMode gtk_widget_real_get_request_mode (GtkWidget *widget); - -static void template_data_free (GtkWidgetTemplate*template_data); - -static void gtk_widget_set_usize_internal (GtkWidget *widget, - int width, - int height); - -static gboolean event_surface_is_still_viewable (GdkEvent *event); - -static gboolean gtk_widget_class_get_visible_by_default (GtkWidgetClass *widget_class); - -static void remove_parent_surface_transform_changed_listener (GtkWidget *widget); -static void add_parent_surface_transform_changed_listener (GtkWidget *widget); -static void gtk_widget_queue_compute_expand (GtkWidget *widget); +static void remove_parent_surface_transform_changed_listener (GtkWidget *widget); +static void add_parent_surface_transform_changed_listener (GtkWidget *widget); +static void gtk_widget_queue_compute_expand (GtkWidget *widget); -/* --- variables --- */ static int GtkWidget_private_offset = 0; static gpointer gtk_widget_parent_class = NULL; static guint widget_signals[LAST_SIGNAL] = { 0 }; -GtkTextDirection gtk_default_direction = GTK_TEXT_DIR_LTR; +static GParamSpec *widget_props[NUM_PROPERTIES] = { NULL, }; +GtkTextDirection gtk_default_direction = GTK_TEXT_DIR_LTR; -static GQuark quark_pango_context = 0; -static GQuark quark_mnemonic_labels = 0; +static GQuark quark_pango_context = 0; +static GQuark quark_mnemonic_labels = 0; static GQuark quark_size_groups = 0; static GQuark quark_auto_children = 0; static GQuark quark_action_muxer = 0; static GQuark quark_font_options = 0; static GQuark quark_font_map = 0; +static GQuark quark_builder_set_id = 0; -/* --- functions --- */ GType gtk_widget_get_type (void) { @@ -680,16 +629,16 @@ gtk_widget_get_type (void) { const GTypeInfo widget_info = { - sizeof (GtkWidgetClass), - gtk_widget_base_class_init, - (GBaseFinalizeFunc) gtk_widget_base_class_finalize, - (GClassInitFunc) gtk_widget_class_init, - NULL, /* class_finalize */ - NULL, /* class_init */ - sizeof (GtkWidget), - 0, /* n_preallocs */ - gtk_widget_init, - NULL, /* value_table */ + sizeof (GtkWidgetClass), + gtk_widget_base_class_init, + (GBaseFinalizeFunc) gtk_widget_base_class_finalize, + (GClassInitFunc) gtk_widget_class_init, + NULL, /* class_finalize */ + NULL, /* class_init */ + sizeof (GtkWidget), + 0, /* n_preallocs */ + gtk_widget_init, + NULL, /* value_table */ }; const GInterfaceInfo accessible_info = @@ -701,16 +650,16 @@ gtk_widget_get_type (void) const GInterfaceInfo buildable_info = { - (GInterfaceInitFunc) gtk_widget_buildable_interface_init, - (GInterfaceFinalizeFunc) NULL, - NULL /* interface data */ + (GInterfaceInitFunc) gtk_widget_buildable_interface_init, + (GInterfaceFinalizeFunc) NULL, + NULL /* interface data */ }; const GInterfaceInfo constraint_target_info = { - (GInterfaceInitFunc) NULL, - (GInterfaceFinalizeFunc) NULL, - NULL /* interface data */ + (GInterfaceInitFunc) NULL, + (GInterfaceFinalizeFunc) NULL, + NULL /* interface data */ }; widget_type = g_type_register_static (G_TYPE_INITIALLY_UNOWNED, g_intern_static_string ("GtkWidget"), @@ -718,8 +667,7 @@ gtk_widget_get_type (void) g_type_add_class_private (widget_type, sizeof (GtkWidgetClassPrivate)); - GtkWidget_private_offset = - g_type_add_instance_private (widget_type, sizeof (GtkWidgetPrivate)); + GtkWidget_private_offset = g_type_add_instance_private (widget_type, sizeof (GtkWidgetPrivate)); g_type_add_interface_static (widget_type, GTK_TYPE_ACCESSIBLE, &accessible_info); @@ -745,7 +693,7 @@ gtk_widget_base_class_init (gpointer g_class) GtkWidgetClassPrivate *priv; priv = klass->priv = G_TYPE_CLASS_GET_PRIVATE (g_class, GTK_TYPE_WIDGET, GtkWidgetClassPrivate); - + priv->template = NULL; if (priv->shortcuts == NULL) @@ -801,7 +749,7 @@ gtk_widget_real_contains (GtkWidget *widget, **/ void _gtk_widget_grab_notify (GtkWidget *widget, - gboolean was_grabbed) + gboolean was_grabbed) { GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget); GList *l; @@ -865,6 +813,349 @@ gtk_widget_constructed (GObject *object) } static void +gtk_widget_real_measure (GtkWidget *widget, + GtkOrientation orientation, + int for_size, + int *minimum, + int *natural, + int *minimum_baseline, + int *natural_baseline) +{ + *minimum = 0; + *natural = 0; +} + +static GtkSizeRequestMode +gtk_widget_real_get_request_mode (GtkWidget *widget) +{ + /* By default widgets don't trade size at all. */ + return GTK_SIZE_REQUEST_CONSTANT_SIZE; +} + +static void +gtk_widget_real_state_flags_changed (GtkWidget *widget, + GtkStateFlags old_state) +{ +} + +static gboolean +gtk_widget_real_query_tooltip (GtkWidget *widget, + int x, + int y, + gboolean keyboard_tip, + GtkTooltip *tooltip) +{ + const char *tooltip_markup; + gboolean has_tooltip; + + has_tooltip = gtk_widget_get_has_tooltip (widget); + tooltip_markup = gtk_widget_get_tooltip_markup (widget); + if (tooltip_markup == NULL) + tooltip_markup = gtk_widget_get_tooltip_text (widget); + + if (has_tooltip && tooltip_markup != NULL) + { + gtk_tooltip_set_markup (tooltip, tooltip_markup); + return TRUE; + } + + return FALSE; +} + +static void +gtk_widget_real_size_allocate (GtkWidget *widget, + int width, + int height, + int baseline) +{ +} + +static void +gtk_widget_set_accessible_role (GtkWidget *self, + GtkAccessibleRole role) +{ + GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self); + + if (priv->at_context == NULL || !gtk_at_context_is_realized (priv->at_context)) + { + priv->accessible_role = role; + + if (priv->at_context != NULL) + gtk_at_context_set_accessible_role (priv->at_context, role); + + g_object_notify (G_OBJECT (self), "accessible-role"); + } + else + { + char *role_str = g_enum_to_string (GTK_TYPE_ACCESSIBLE_ROLE, priv->accessible_role); + + g_critical ("Widget of type “%s” already has an accessible role of type “%s”", + G_OBJECT_TYPE_NAME (self), + role_str); + g_free (role_str); + } +} + +static GtkAccessibleRole +gtk_widget_get_accessible_role (GtkWidget *self) +{ + GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self); + GtkATContext *context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (self)); + GtkWidgetClassPrivate *class_priv; + + if (context != NULL && gtk_at_context_is_realized (context)) + return gtk_at_context_get_accessible_role (context); + + if (priv->accessible_role != GTK_ACCESSIBLE_ROLE_WIDGET) + return priv->accessible_role; + + class_priv = GTK_WIDGET_GET_CLASS (self)->priv; + + return class_priv->accessible_role; +} + +static void +gtk_widget_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GtkWidget *widget = GTK_WIDGET (object); + GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget); + + switch (prop_id) + { + case PROP_NAME: + gtk_widget_set_name (widget, g_value_get_string (value)); + break; + case PROP_WIDTH_REQUEST: + gtk_widget_set_usize_internal (widget, g_value_get_int (value), -2); + break; + case PROP_HEIGHT_REQUEST: + gtk_widget_set_usize_internal (widget, -2, g_value_get_int (value)); + break; + case PROP_VISIBLE: + gtk_widget_set_visible (widget, g_value_get_boolean (value)); + break; + case PROP_SENSITIVE: + gtk_widget_set_sensitive (widget, g_value_get_boolean (value)); + break; + case PROP_CAN_FOCUS: + gtk_widget_set_can_focus (widget, g_value_get_boolean (value)); + break; + case PROP_FOCUSABLE: + gtk_widget_set_focusable (widget, g_value_get_boolean (value)); + break; + case PROP_CAN_TARGET: + gtk_widget_set_can_target (widget, g_value_get_boolean (value)); + break; + case PROP_FOCUS_ON_CLICK: + gtk_widget_set_focus_on_click (widget, g_value_get_boolean (value)); + break; + case PROP_RECEIVES_DEFAULT: + gtk_widget_set_receives_default (widget, g_value_get_boolean (value)); + break; + case PROP_CURSOR: + gtk_widget_set_cursor (widget, g_value_get_object (value)); + break; + case PROP_HAS_TOOLTIP: + gtk_widget_set_has_tooltip (widget, g_value_get_boolean (value)); + break; + case PROP_TOOLTIP_MARKUP: + gtk_widget_set_tooltip_markup (widget, g_value_get_string (value)); + break; + case PROP_TOOLTIP_TEXT: + gtk_widget_set_tooltip_text (widget, g_value_get_string (value)); + break; + case PROP_HALIGN: + gtk_widget_set_halign (widget, g_value_get_enum (value)); + break; + case PROP_VALIGN: + gtk_widget_set_valign (widget, g_value_get_enum (value)); + break; + case PROP_MARGIN_START: + gtk_widget_set_margin_start (widget, g_value_get_int (value)); + break; + case PROP_MARGIN_END: + gtk_widget_set_margin_end (widget, g_value_get_int (value)); + break; + case PROP_MARGIN_TOP: + gtk_widget_set_margin_top (widget, g_value_get_int (value)); + break; + case PROP_MARGIN_BOTTOM: + gtk_widget_set_margin_bottom (widget, g_value_get_int (value)); + break; + case PROP_HEXPAND: + gtk_widget_set_hexpand (widget, g_value_get_boolean (value)); + break; + case PROP_HEXPAND_SET: + gtk_widget_set_hexpand_set (widget, g_value_get_boolean (value)); + break; + case PROP_VEXPAND: + gtk_widget_set_vexpand (widget, g_value_get_boolean (value)); + break; + case PROP_VEXPAND_SET: + gtk_widget_set_vexpand_set (widget, g_value_get_boolean (value)); + break; + case PROP_OPACITY: + gtk_widget_set_opacity (widget, g_value_get_double (value)); + break; + case PROP_OVERFLOW: + gtk_widget_set_overflow (widget, g_value_get_enum (value)); + break; + case PROP_CSS_NAME: + if (g_value_get_string (value) != NULL) + gtk_css_node_set_name (priv->cssnode, g_quark_from_string (g_value_get_string (value))); + break; + case PROP_CSS_CLASSES: + gtk_widget_set_css_classes (widget, g_value_get_boxed (value)); + break; + case PROP_LAYOUT_MANAGER: + gtk_widget_set_layout_manager (widget, g_value_dup_object (value)); + break; + case PROP_ACCESSIBLE_ROLE: + gtk_widget_set_accessible_role (widget, g_value_get_enum (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gtk_widget_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GtkWidget *widget = GTK_WIDGET (object); + GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget); + + switch (prop_id) + { + case PROP_NAME: + if (priv->name) + g_value_set_string (value, priv->name); + else + g_value_set_static_string (value, ""); + break; + case PROP_PARENT: + g_value_set_object (value, priv->parent); + break; + case PROP_ROOT: + g_value_set_object (value, priv->root); + break; + case PROP_WIDTH_REQUEST: + { + int w; + gtk_widget_get_size_request (widget, &w, NULL); + g_value_set_int (value, w); + } + break; + case PROP_HEIGHT_REQUEST: + { + int h; + gtk_widget_get_size_request (widget, NULL, &h); + g_value_set_int (value, h); + } + break; + case PROP_VISIBLE: + g_value_set_boolean (value, _gtk_widget_get_visible (widget)); + break; + case PROP_SENSITIVE: + g_value_set_boolean (value, gtk_widget_get_sensitive (widget)); + break; + case PROP_CAN_FOCUS: + g_value_set_boolean (value, gtk_widget_get_can_focus (widget)); + break; + case PROP_FOCUSABLE: + g_value_set_boolean (value, gtk_widget_get_focusable (widget)); + break; + case PROP_HAS_FOCUS: + g_value_set_boolean (value, gtk_widget_has_focus (widget)); + break; + case PROP_CAN_TARGET: + g_value_set_boolean (value, gtk_widget_get_can_target (widget)); + break; + case PROP_FOCUS_ON_CLICK: + g_value_set_boolean (value, gtk_widget_get_focus_on_click (widget)); + break; + case PROP_HAS_DEFAULT: + g_value_set_boolean (value, gtk_widget_has_default (widget)); + break; + case PROP_RECEIVES_DEFAULT: + g_value_set_boolean (value, gtk_widget_get_receives_default (widget)); + break; + case PROP_CURSOR: + g_value_set_object (value, gtk_widget_get_cursor (widget)); + break; + case PROP_HAS_TOOLTIP: + g_value_set_boolean (value, gtk_widget_get_has_tooltip (widget)); + break; + case PROP_TOOLTIP_TEXT: + g_value_set_string (value, gtk_widget_get_tooltip_text (widget)); + break; + case PROP_TOOLTIP_MARKUP: + g_value_set_string (value, gtk_widget_get_tooltip_markup (widget)); + break; + case PROP_HALIGN: + g_value_set_enum (value, gtk_widget_get_halign (widget)); + break; + case PROP_VALIGN: + g_value_set_enum (value, gtk_widget_get_valign (widget)); + break; + case PROP_MARGIN_START: + g_value_set_int (value, gtk_widget_get_margin_start (widget)); + break; + case PROP_MARGIN_END: + g_value_set_int (value, gtk_widget_get_margin_end (widget)); + break; + case PROP_MARGIN_TOP: + g_value_set_int (value, gtk_widget_get_margin_top (widget)); + break; + case PROP_MARGIN_BOTTOM: + g_value_set_int (value, gtk_widget_get_margin_bottom (widget)); + break; + case PROP_HEXPAND: + g_value_set_boolean (value, gtk_widget_get_hexpand (widget)); + break; + case PROP_HEXPAND_SET: + g_value_set_boolean (value, gtk_widget_get_hexpand_set (widget)); + break; + case PROP_VEXPAND: + g_value_set_boolean (value, gtk_widget_get_vexpand (widget)); + break; + case PROP_VEXPAND_SET: + g_value_set_boolean (value, gtk_widget_get_vexpand_set (widget)); + break; + case PROP_OPACITY: + g_value_set_double (value, gtk_widget_get_opacity (widget)); + break; + case PROP_OVERFLOW: + g_value_set_enum (value, gtk_widget_get_overflow (widget)); + break; + case PROP_SCALE_FACTOR: + g_value_set_int (value, gtk_widget_get_scale_factor (widget)); + break; + case PROP_CSS_NAME: + g_value_set_string (value, gtk_widget_get_css_name (widget)); + break; + case PROP_CSS_CLASSES: + g_value_take_boxed (value, gtk_widget_get_css_classes (widget)); + break; + case PROP_LAYOUT_MANAGER: + g_value_set_object (value, gtk_widget_get_layout_manager (widget)); + break; + case PROP_ACCESSIBLE_ROLE: + g_value_set_enum (value, gtk_widget_get_accessible_role (widget)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void gtk_widget_class_init (GtkWidgetClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); @@ -1372,12 +1663,12 @@ gtk_widget_class_init (GtkWidgetClass *klass) */ widget_signals[SHOW] = g_signal_new (I_("show"), - G_TYPE_FROM_CLASS (gobject_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GtkWidgetClass, show), - NULL, NULL, + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GtkWidgetClass, show), + NULL, NULL, NULL, - G_TYPE_NONE, 0); + G_TYPE_NONE, 0); /** * GtkWidget::hide: @@ -1388,12 +1679,12 @@ gtk_widget_class_init (GtkWidgetClass *klass) */ widget_signals[HIDE] = g_signal_new (I_("hide"), - G_TYPE_FROM_CLASS (gobject_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GtkWidgetClass, hide), - NULL, NULL, + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GtkWidgetClass, hide), + NULL, NULL, NULL, - G_TYPE_NONE, 0); + G_TYPE_NONE, 0); /** * GtkWidget::map: @@ -1410,12 +1701,12 @@ gtk_widget_class_init (GtkWidgetClass *klass) */ widget_signals[MAP] = g_signal_new (I_("map"), - G_TYPE_FROM_CLASS (gobject_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GtkWidgetClass, map), - NULL, NULL, + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GtkWidgetClass, map), + NULL, NULL, NULL, - G_TYPE_NONE, 0); + G_TYPE_NONE, 0); /** * GtkWidget::unmap: @@ -1430,12 +1721,12 @@ gtk_widget_class_init (GtkWidgetClass *klass) */ widget_signals[UNMAP] = g_signal_new (I_("unmap"), - G_TYPE_FROM_CLASS (gobject_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GtkWidgetClass, unmap), - NULL, NULL, + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GtkWidgetClass, unmap), + NULL, NULL, NULL, - G_TYPE_NONE, 0); + G_TYPE_NONE, 0); /** * GtkWidget::realize: @@ -1447,12 +1738,12 @@ gtk_widget_class_init (GtkWidgetClass *klass) */ widget_signals[REALIZE] = g_signal_new (I_("realize"), - G_TYPE_FROM_CLASS (gobject_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GtkWidgetClass, realize), - NULL, NULL, + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GtkWidgetClass, realize), + NULL, NULL, NULL, - G_TYPE_NONE, 0); + G_TYPE_NONE, 0); /** * GtkWidget::unrealize: @@ -1465,12 +1756,12 @@ gtk_widget_class_init (GtkWidgetClass *klass) */ widget_signals[UNREALIZE] = g_signal_new (I_("unrealize"), - G_TYPE_FROM_CLASS (gobject_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GtkWidgetClass, unrealize), - NULL, NULL, + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkWidgetClass, unrealize), + NULL, NULL, NULL, - G_TYPE_NONE, 0); + G_TYPE_NONE, 0); /** * GtkWidget::state-flags-changed: @@ -1500,13 +1791,13 @@ gtk_widget_class_init (GtkWidgetClass *klass) */ widget_signals[DIRECTION_CHANGED] = g_signal_new (I_("direction-changed"), - G_TYPE_FROM_CLASS (gobject_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GtkWidgetClass, direction_changed), - NULL, NULL, - NULL, - G_TYPE_NONE, 1, - GTK_TYPE_TEXT_DIRECTION); + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GtkWidgetClass, direction_changed), + NULL, NULL, + NULL, + G_TYPE_NONE, 1, + GTK_TYPE_TEXT_DIRECTION); /** * GtkWidget::mnemonic-activate: @@ -1521,13 +1812,13 @@ gtk_widget_class_init (GtkWidgetClass *klass) */ widget_signals[MNEMONIC_ACTIVATE] = g_signal_new (I_("mnemonic-activate"), - G_TYPE_FROM_CLASS (gobject_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GtkWidgetClass, mnemonic_activate), - _gtk_boolean_handled_accumulator, NULL, - _gtk_marshal_BOOLEAN__BOOLEAN, - G_TYPE_BOOLEAN, 1, - G_TYPE_BOOLEAN); + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkWidgetClass, mnemonic_activate), + _gtk_boolean_handled_accumulator, NULL, + _gtk_marshal_BOOLEAN__BOOLEAN, + G_TYPE_BOOLEAN, 1, + G_TYPE_BOOLEAN); g_signal_set_va_marshaller (widget_signals[MNEMONIC_ACTIVATE], G_TYPE_FROM_CLASS (gobject_class), _gtk_marshal_BOOLEAN__BOOLEANv); @@ -1602,16 +1893,16 @@ gtk_widget_class_init (GtkWidgetClass *klass) */ widget_signals[QUERY_TOOLTIP] = g_signal_new (I_("query-tooltip"), - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GtkWidgetClass, query_tooltip), - _gtk_boolean_handled_accumulator, NULL, - _gtk_marshal_BOOLEAN__INT_INT_BOOLEAN_OBJECT, - G_TYPE_BOOLEAN, 4, - G_TYPE_INT, - G_TYPE_INT, - G_TYPE_BOOLEAN, - GTK_TYPE_TOOLTIP); + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkWidgetClass, query_tooltip), + _gtk_boolean_handled_accumulator, NULL, + _gtk_marshal_BOOLEAN__INT_INT_BOOLEAN_OBJECT, + G_TYPE_BOOLEAN, 4, + G_TYPE_INT, + G_TYPE_INT, + G_TYPE_BOOLEAN, + GTK_TYPE_TOOLTIP); g_signal_set_va_marshaller (widget_signals[QUERY_TOOLTIP], G_TYPE_FROM_CLASS (klass), _gtk_marshal_BOOLEAN__INT_INT_BOOLEAN_OBJECTv); @@ -1621,252 +1912,31 @@ gtk_widget_class_init (GtkWidgetClass *klass) } static void -gtk_widget_base_class_finalize (GtkWidgetClass *klass) -{ - - template_data_free (klass->priv->template); - g_object_unref (klass->priv->shortcuts); -} - -static void -gtk_widget_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) +template_child_class_free (AutomaticChildClass *child_class) { - GtkWidget *widget = GTK_WIDGET (object); - GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget); - - switch (prop_id) + if (child_class) { - case PROP_NAME: - gtk_widget_set_name (widget, g_value_get_string (value)); - break; - case PROP_WIDTH_REQUEST: - gtk_widget_set_usize_internal (widget, g_value_get_int (value), -2); - break; - case PROP_HEIGHT_REQUEST: - gtk_widget_set_usize_internal (widget, -2, g_value_get_int (value)); - break; - case PROP_VISIBLE: - gtk_widget_set_visible (widget, g_value_get_boolean (value)); - break; - case PROP_SENSITIVE: - gtk_widget_set_sensitive (widget, g_value_get_boolean (value)); - break; - case PROP_CAN_FOCUS: - gtk_widget_set_can_focus (widget, g_value_get_boolean (value)); - break; - case PROP_FOCUSABLE: - gtk_widget_set_focusable (widget, g_value_get_boolean (value)); - break; - case PROP_CAN_TARGET: - gtk_widget_set_can_target (widget, g_value_get_boolean (value)); - break; - case PROP_FOCUS_ON_CLICK: - gtk_widget_set_focus_on_click (widget, g_value_get_boolean (value)); - break; - case PROP_RECEIVES_DEFAULT: - gtk_widget_set_receives_default (widget, g_value_get_boolean (value)); - break; - case PROP_CURSOR: - gtk_widget_set_cursor (widget, g_value_get_object (value)); - break; - case PROP_HAS_TOOLTIP: - gtk_widget_set_has_tooltip (widget, g_value_get_boolean (value)); - break; - case PROP_TOOLTIP_MARKUP: - gtk_widget_set_tooltip_markup (widget, g_value_get_string (value)); - break; - case PROP_TOOLTIP_TEXT: - gtk_widget_set_tooltip_text (widget, g_value_get_string (value)); - break; - case PROP_HALIGN: - gtk_widget_set_halign (widget, g_value_get_enum (value)); - break; - case PROP_VALIGN: - gtk_widget_set_valign (widget, g_value_get_enum (value)); - break; - case PROP_MARGIN_START: - gtk_widget_set_margin_start (widget, g_value_get_int (value)); - break; - case PROP_MARGIN_END: - gtk_widget_set_margin_end (widget, g_value_get_int (value)); - break; - case PROP_MARGIN_TOP: - gtk_widget_set_margin_top (widget, g_value_get_int (value)); - break; - case PROP_MARGIN_BOTTOM: - gtk_widget_set_margin_bottom (widget, g_value_get_int (value)); - break; - case PROP_HEXPAND: - gtk_widget_set_hexpand (widget, g_value_get_boolean (value)); - break; - case PROP_HEXPAND_SET: - gtk_widget_set_hexpand_set (widget, g_value_get_boolean (value)); - break; - case PROP_VEXPAND: - gtk_widget_set_vexpand (widget, g_value_get_boolean (value)); - break; - case PROP_VEXPAND_SET: - gtk_widget_set_vexpand_set (widget, g_value_get_boolean (value)); - break; - case PROP_OPACITY: - gtk_widget_set_opacity (widget, g_value_get_double (value)); - break; - case PROP_OVERFLOW: - gtk_widget_set_overflow (widget, g_value_get_enum (value)); - break; - case PROP_CSS_NAME: - if (g_value_get_string (value) != NULL) - gtk_css_node_set_name (priv->cssnode, g_quark_from_string (g_value_get_string (value))); - break; - case PROP_CSS_CLASSES: - gtk_widget_set_css_classes (widget, g_value_get_boxed (value)); - break; - case PROP_LAYOUT_MANAGER: - gtk_widget_set_layout_manager (widget, g_value_dup_object (value)); - break; - case PROP_ACCESSIBLE_ROLE: - gtk_widget_set_accessible_role (widget, g_value_get_enum (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; + g_free (child_class->name); + g_slice_free (AutomaticChildClass, child_class); } } static void -gtk_widget_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) +gtk_widget_base_class_finalize (GtkWidgetClass *klass) { - GtkWidget *widget = GTK_WIDGET (object); - GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget); + GtkWidgetTemplate *template_data = klass->priv->template; - switch (prop_id) + if (template_data) { - case PROP_NAME: - if (priv->name) - g_value_set_string (value, priv->name); - else - g_value_set_static_string (value, ""); - break; - case PROP_PARENT: - g_value_set_object (value, priv->parent); - break; - case PROP_ROOT: - g_value_set_object (value, priv->root); - break; - case PROP_WIDTH_REQUEST: - { - int w; - gtk_widget_get_size_request (widget, &w, NULL); - g_value_set_int (value, w); - } - break; - case PROP_HEIGHT_REQUEST: - { - int h; - gtk_widget_get_size_request (widget, NULL, &h); - g_value_set_int (value, h); - } - break; - case PROP_VISIBLE: - g_value_set_boolean (value, _gtk_widget_get_visible (widget)); - break; - case PROP_SENSITIVE: - g_value_set_boolean (value, gtk_widget_get_sensitive (widget)); - break; - case PROP_CAN_FOCUS: - g_value_set_boolean (value, gtk_widget_get_can_focus (widget)); - break; - case PROP_FOCUSABLE: - g_value_set_boolean (value, gtk_widget_get_focusable (widget)); - break; - case PROP_HAS_FOCUS: - g_value_set_boolean (value, gtk_widget_has_focus (widget)); - break; - case PROP_CAN_TARGET: - g_value_set_boolean (value, gtk_widget_get_can_target (widget)); - break; - case PROP_FOCUS_ON_CLICK: - g_value_set_boolean (value, gtk_widget_get_focus_on_click (widget)); - break; - case PROP_HAS_DEFAULT: - g_value_set_boolean (value, gtk_widget_has_default (widget)); - break; - case PROP_RECEIVES_DEFAULT: - g_value_set_boolean (value, gtk_widget_get_receives_default (widget)); - break; - case PROP_CURSOR: - g_value_set_object (value, gtk_widget_get_cursor (widget)); - break; - case PROP_HAS_TOOLTIP: - g_value_set_boolean (value, gtk_widget_get_has_tooltip (widget)); - break; - case PROP_TOOLTIP_TEXT: - g_value_set_string (value, gtk_widget_get_tooltip_text (widget)); - break; - case PROP_TOOLTIP_MARKUP: - g_value_set_string (value, gtk_widget_get_tooltip_markup (widget)); - break; - case PROP_HALIGN: - g_value_set_enum (value, gtk_widget_get_halign (widget)); - break; - case PROP_VALIGN: - g_value_set_enum (value, gtk_widget_get_valign (widget)); - break; - case PROP_MARGIN_START: - g_value_set_int (value, gtk_widget_get_margin_start (widget)); - break; - case PROP_MARGIN_END: - g_value_set_int (value, gtk_widget_get_margin_end (widget)); - break; - case PROP_MARGIN_TOP: - g_value_set_int (value, gtk_widget_get_margin_top (widget)); - break; - case PROP_MARGIN_BOTTOM: - g_value_set_int (value, gtk_widget_get_margin_bottom (widget)); - break; - case PROP_HEXPAND: - g_value_set_boolean (value, gtk_widget_get_hexpand (widget)); - break; - case PROP_HEXPAND_SET: - g_value_set_boolean (value, gtk_widget_get_hexpand_set (widget)); - break; - case PROP_VEXPAND: - g_value_set_boolean (value, gtk_widget_get_vexpand (widget)); - break; - case PROP_VEXPAND_SET: - g_value_set_boolean (value, gtk_widget_get_vexpand_set (widget)); - break; - case PROP_OPACITY: - g_value_set_double (value, gtk_widget_get_opacity (widget)); - break; - case PROP_OVERFLOW: - g_value_set_enum (value, gtk_widget_get_overflow (widget)); - break; - case PROP_SCALE_FACTOR: - g_value_set_int (value, gtk_widget_get_scale_factor (widget)); - break; - case PROP_CSS_NAME: - g_value_set_string (value, gtk_widget_get_css_name (widget)); - break; - case PROP_CSS_CLASSES: - g_value_take_boxed (value, gtk_widget_get_css_classes (widget)); - break; - case PROP_LAYOUT_MANAGER: - g_value_set_object (value, gtk_widget_get_layout_manager (widget)); - break; - case PROP_ACCESSIBLE_ROLE: - g_value_set_enum (value, gtk_widget_get_accessible_role (widget)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; + g_bytes_unref (template_data->data); + g_slist_free_full (template_data->children, (GDestroyNotify)template_child_class_free); + + g_object_unref (template_data->scope); + + g_slice_free (GtkWidgetTemplate, template_data); } + + g_object_unref (klass->priv->shortcuts); } static void @@ -2206,6 +2276,12 @@ _gtk_widget_cancel_sequence (GtkWidget *widget, return handled; } +static gboolean +gtk_widget_class_get_visible_by_default (GtkWidgetClass *widget_class) +{ + return !g_type_is_a (G_TYPE_FROM_CLASS (widget_class), GTK_TYPE_NATIVE); +} + static void gtk_widget_init (GTypeInstance *instance, gpointer g_class) { @@ -2661,7 +2737,7 @@ gtk_widget_hide (GtkWidget *widget) parent = gtk_widget_get_parent (widget); if (parent) - gtk_widget_queue_resize (parent); + gtk_widget_queue_resize (parent); gtk_widget_queue_allocate (widget); @@ -3349,21 +3425,18 @@ void gtk_widget_get_surface_allocation (GtkWidget *widget, GtkAllocation *allocation) { - GtkWidget *parent; + GtkNative *native; graphene_rect_t bounds; double nx, ny; - /* Don't consider the parent == widget case here. */ - parent = _gtk_widget_get_parent (widget); - while (parent && !GTK_IS_NATIVE (parent)) - parent = _gtk_widget_get_parent (parent); + native = gtk_widget_get_native (widget); - g_assert (GTK_IS_WINDOW (parent) || GTK_IS_POPOVER (parent)); - gtk_native_get_surface_transform (GTK_NATIVE (parent), &nx, &ny); + g_assert (GTK_IS_WINDOW (native) || GTK_IS_POPOVER (native)); + gtk_native_get_surface_transform (native, &nx, &ny); - if (gtk_widget_compute_bounds (widget, parent, &bounds)) + if (gtk_widget_compute_bounds (widget, GTK_WIDGET (native), &bounds)) { - *allocation = (GtkAllocation){ + *allocation = (GtkAllocation) { floorf (bounds.origin.x) + nx, floorf (bounds.origin.y) + ny, ceilf (bounds.size.width), @@ -3444,7 +3517,7 @@ gtk_widget_get_resize_needed (GtkWidget *widget) /* * gtk_widget_queue_resize_internal: * @widget: a #GtkWidget - * + * * Queue a resize on a widget, and on all other widgets grouped with this widget. */ static void @@ -3465,12 +3538,10 @@ gtk_widget_queue_resize_internal (GtkWidget *widget) groups = _gtk_widget_get_sizegroups (widget); for (l = groups; l; l = l->next) - { - for (widgets = gtk_size_group_get_widgets (l->data); widgets; widgets = widgets->next) - { + { + for (widgets = gtk_size_group_get_widgets (l->data); widgets; widgets = widgets->next) gtk_widget_queue_resize_internal (widgets->data); - } - } + } if (_gtk_widget_get_visible (widget)) { @@ -3496,7 +3567,7 @@ gtk_widget_queue_resize_internal (GtkWidget *widget) * queues a resize to ensure there’s enough space for the new text. * * Note that you cannot call gtk_widget_queue_resize() on a widget - * from inside its implementation of the GtkWidgetClass::size_allocate + * from inside its implementation of the GtkWidgetClass::size_allocate * virtual method. Calls to gtk_widget_queue_resize() from inside * GtkWidgetClass::size_allocate will be silently ignored. **/ @@ -3666,17 +3737,17 @@ adjust_for_align (GtkAlign align, break; case GTK_ALIGN_END: if (*allocated_size > natural_size) - { - *allocated_pos += (*allocated_size - natural_size); - *allocated_size = natural_size; - } + { + *allocated_pos += (*allocated_size - natural_size); + *allocated_size = natural_size; + } break; case GTK_ALIGN_CENTER: if (*allocated_size > natural_size) - { - *allocated_pos += (*allocated_size - natural_size) / 2; - *allocated_size = MIN (*allocated_size, natural_size); - } + { + *allocated_pos += (*allocated_size - natural_size) / 2; + *allocated_size = MIN (*allocated_size, natural_size); + } break; } } @@ -3963,7 +4034,7 @@ out: **/ GtkWidget * gtk_widget_common_ancestor (GtkWidget *widget_a, - GtkWidget *widget_b) + GtkWidget *widget_b) { GtkWidget *parent_a; GtkWidget *parent_b; @@ -4086,14 +4157,6 @@ gtk_widget_compute_point (GtkWidget *widget, return TRUE; } -static void -gtk_widget_real_size_allocate (GtkWidget *widget, - int width, - int height, - int baseline) -{ -} - /** * gtk_widget_class_add_binding: (skip) * @widget_class: the class to add the binding to @@ -4291,10 +4354,10 @@ gtk_widget_mnemonic_activate (GtkWidget *widget, handled = TRUE; else g_signal_emit (widget, - widget_signals[MNEMONIC_ACTIVATE], - 0, - group_cycling, - &handled); + widget_signals[MNEMONIC_ACTIVATE], + 0, + group_cycling, + &handled); return handled; } @@ -4329,7 +4392,7 @@ gtk_widget_real_mnemonic_activate (GtkWidget *widget, else { g_warning ("widget '%s' isn't suitable for mnemonic activation", - G_OBJECT_TYPE_NAME (widget)); + G_OBJECT_TYPE_NAME (widget)); gtk_widget_error_bell (widget); } return TRUE; @@ -4455,34 +4518,6 @@ gtk_widget_handle_crossing (GtkWidget *widget, } static gboolean -translate_event_coordinates (GdkEvent *event, - double *x, - double *y, - GtkWidget *widget); - -gboolean -_gtk_widget_captured_event (GtkWidget *widget, - GdkEvent *event, - GtkWidget *target) -{ - gboolean return_val = FALSE; - double x, y; - - g_return_val_if_fail (GTK_IS_WIDGET (widget), TRUE); - g_return_val_if_fail (WIDGET_REALIZED_FOR_EVENT (widget, event), TRUE); - - if (!event_surface_is_still_viewable (event)) - return TRUE; - - translate_event_coordinates (event, &x, &y, widget); - - return_val = gtk_widget_run_controllers (widget, event, target, x, y, GTK_PHASE_CAPTURE); - return_val |= !WIDGET_REALIZED_FOR_EVENT (widget, event); - - return return_val; -} - -static gboolean event_surface_is_still_viewable (GdkEvent *event) { /* Check that we think the event's window is viewable before @@ -4555,6 +4590,28 @@ translate_event_coordinates (GdkEvent *event, } gboolean +_gtk_widget_captured_event (GtkWidget *widget, + GdkEvent *event, + GtkWidget *target) +{ + gboolean return_val = FALSE; + double x, y; + + g_return_val_if_fail (GTK_IS_WIDGET (widget), TRUE); + g_return_val_if_fail (WIDGET_REALIZED_FOR_EVENT (widget, event), TRUE); + + if (!event_surface_is_still_viewable (event)) + return TRUE; + + translate_event_coordinates (event, &x, &y, widget); + + return_val = gtk_widget_run_controllers (widget, event, target, x, y, GTK_PHASE_CAPTURE); + return_val |= !WIDGET_REALIZED_FOR_EVENT (widget, event); + + return return_val; +} + +gboolean gtk_widget_event (GtkWidget *widget, GdkEvent *event, GtkWidget *target) @@ -4752,30 +4809,6 @@ gtk_widget_grab_focus_child (GtkWidget *widget) return FALSE; } -static gboolean -gtk_widget_real_query_tooltip (GtkWidget *widget, - int x, - int y, - gboolean keyboard_tip, - GtkTooltip *tooltip) -{ - const char *tooltip_markup; - gboolean has_tooltip; - - has_tooltip = gtk_widget_get_has_tooltip (widget); - tooltip_markup = gtk_widget_get_tooltip_markup (widget); - if (tooltip_markup == NULL) - tooltip_markup = gtk_widget_get_tooltip_text (widget); - - if (has_tooltip && tooltip_markup != NULL) - { - gtk_tooltip_set_markup (tooltip, tooltip_markup); - return TRUE; - } - - return FALSE; -} - gboolean gtk_widget_query_tooltip (GtkWidget *widget, int x, @@ -4797,12 +4830,6 @@ gtk_widget_query_tooltip (GtkWidget *widget, } static void -gtk_widget_real_state_flags_changed (GtkWidget *widget, - GtkStateFlags old_state) -{ -} - -static void gtk_widget_real_css_changed (GtkWidget *widget, GtkCssStyleChange *change) { @@ -5200,7 +5227,7 @@ gtk_widget_is_focus (GtkWidget *widget) **/ void gtk_widget_set_focus_on_click (GtkWidget *widget, - gboolean focus_on_click) + gboolean focus_on_click) { GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget); @@ -5364,8 +5391,8 @@ _gtk_widget_set_has_grab (GtkWidget *widget, * of alphanumeric symbols, dashes and underscores will suffice. */ void -gtk_widget_set_name (GtkWidget *widget, - const char *name) +gtk_widget_set_name (GtkWidget *widget, + const char *name) { GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget); @@ -6221,9 +6248,9 @@ gtk_widget_get_pango_context (GtkWidget *widget) { context = gtk_widget_create_pango_context (GTK_WIDGET (widget)); g_object_set_qdata_full (G_OBJECT (widget), - quark_pango_context, - context, - g_object_unref); + quark_pango_context, + context, + g_object_unref); } return context; @@ -6260,8 +6287,8 @@ update_pango_context (GtkWidget *widget, pango_font_description_free (font_desc); pango_context_set_base_dir (context, - _gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR ? - PANGO_DIRECTION_LTR : PANGO_DIRECTION_RTL); + _gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR ? + PANGO_DIRECTION_LTR : PANGO_DIRECTION_RTL); pango_cairo_context_set_resolution (context, _gtk_css_number_value_get (style->core->dpi, 100)); @@ -6443,8 +6470,8 @@ gtk_widget_create_pango_context (GtkWidget *widget) * Returns: (transfer full): the new #PangoLayout **/ PangoLayout * -gtk_widget_create_pango_layout (GtkWidget *widget, - const char *text) +gtk_widget_create_pango_layout (GtkWidget *widget, + const char *text) { PangoLayout *layout; PangoContext *context; @@ -6510,17 +6537,17 @@ gtk_widget_set_child_visible (GtkWidget *widget, root = _gtk_widget_get_root (widget); if (GTK_WIDGET (root) != widget && GTK_IS_WINDOW (root)) - _gtk_window_unset_focus_and_default (GTK_WINDOW (root), widget); + _gtk_window_unset_focus_and_default (GTK_WINDOW (root), widget); } if (priv->parent && _gtk_widget_get_realized (priv->parent)) { if (_gtk_widget_get_mapped (priv->parent) && - priv->child_visible && - _gtk_widget_get_visible (widget)) - gtk_widget_map (widget); + priv->child_visible && + _gtk_widget_get_visible (widget)) + gtk_widget_map (widget); else - gtk_widget_unmap (widget); + gtk_widget_unmap (widget); } gtk_widget_verify_invariants (widget); @@ -6730,7 +6757,7 @@ gtk_widget_keynav_failed (GtkWidget *widget, g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); g_signal_emit (widget, widget_signals[KEYNAV_FAILED], 0, - direction, &return_val); + direction, &return_val); return return_val; } @@ -6771,9 +6798,9 @@ gtk_widget_error_bell (GtkWidget *widget) } static void -gtk_widget_set_usize_internal (GtkWidget *widget, - int width, - int height) +gtk_widget_set_usize_internal (GtkWidget *widget, + int width, + int height) { GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget); gboolean changed = FALSE; @@ -6808,7 +6835,7 @@ gtk_widget_set_usize_internal (GtkWidget *widget, * @height: height @widget should request, or -1 to unset * * Sets the minimum size of a widget; that is, the widget’s size - * request will be at least @width by @height. You can use this + * request will be at least @width by @height. You can use this * function to force a widget to be larger than it normally would be. * * In most cases, gtk_window_set_default_size() is a better choice for @@ -6913,7 +6940,7 @@ gtk_widget_has_size_request (GtkWidget *widget) **/ GtkWidget* gtk_widget_get_ancestor (GtkWidget *widget, - GType widget_type) + GType widget_type) { g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL); @@ -6961,7 +6988,7 @@ gtk_widget_get_settings (GtkWidget *widget) **/ gboolean gtk_widget_is_ancestor (GtkWidget *widget, - GtkWidget *ancestor) + GtkWidget *ancestor) { g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); g_return_val_if_fail (ancestor != NULL, FALSE); @@ -7117,11 +7144,11 @@ gtk_widget_set_default_direction (GtkTextDirection dir) g_list_foreach (toplevels, (GFunc)g_object_ref, NULL); while (tmp_list) - { - gtk_widget_set_default_direction_recurse (tmp_list->data, old_dir); - g_object_unref (tmp_list->data); - tmp_list = tmp_list->next; - } + { + gtk_widget_set_default_direction_recurse (tmp_list->data, old_dir); + g_object_unref (tmp_list->data); + tmp_list = tmp_list->next; + } g_list_free (toplevels); } @@ -7211,8 +7238,8 @@ typedef struct { } FinalizeAssertion; static void -finalize_assertion_weak_ref (gpointer data, - GObject *where_the_object_was) +finalize_assertion_weak_ref (gpointer data, + GObject *where_the_object_was) { FinalizeAssertion *assertion = (FinalizeAssertion *)data; assertion->did_finalize = TRUE; @@ -7290,43 +7317,43 @@ gtk_widget_real_destroy (GtkWidget *object) #ifdef G_ENABLE_CONSISTENCY_CHECKS for (l = assertions; l; l = l->next) - { - FinalizeAssertion *assertion = l->data; - - if (!assertion->did_finalize) - g_critical ("Automated component '%s' of class '%s' did not finalize in dispose()" - "Current reference count is %d", - assertion->child_class->name, - g_type_name (assertion->widget_type), - assertion->object->ref_count); - - g_slice_free (FinalizeAssertion, assertion); - } + { + FinalizeAssertion *assertion = l->data; + + if (!assertion->did_finalize) + g_critical ("Automated component '%s' of class '%s' did not finalize in dispose()" + "Current reference count is %d", + assertion->child_class->name, + g_type_name (assertion->widget_type), + assertion->object->ref_count); + + g_slice_free (FinalizeAssertion, assertion); + } g_slist_free (assertions); #endif /* G_ENABLE_CONSISTENCY_CHECKS */ /* Set any automatic private data pointers to NULL */ for (class = GTK_WIDGET_GET_CLASS (widget); - GTK_IS_WIDGET_CLASS (class); - class = g_type_class_peek_parent (class)) - { - if (!class->priv->template) - continue; + GTK_IS_WIDGET_CLASS (class); + class = g_type_class_peek_parent (class)) + { + if (!class->priv->template) + continue; - for (l = class->priv->template->children; l; l = l->next) - { - AutomaticChildClass *child_class = l->data; + for (l = class->priv->template->children; l; l = l->next) + { + AutomaticChildClass *child_class = l->data; - if (child_class->offset != 0) - { - gpointer field_p; + if (child_class->offset != 0) + { + gpointer field_p; - /* Nullify instance private data for internal children */ - field_p = G_STRUCT_MEMBER_P (widget, child_class->offset); - (* (gpointer *) field_p) = NULL; - } - } - } + /* Nullify instance private data for internal children */ + field_p = G_STRUCT_MEMBER_P (widget, child_class->offset); + (* (gpointer *) field_p) = NULL; + } + } + } } /* Callers of add_mnemonic_label() should disconnect on ::destroy */ @@ -7625,9 +7652,9 @@ _gtk_widget_list_devices (GtkWidget *widget, */ void _gtk_widget_synthesize_crossing (GtkWidget *from, - GtkWidget *to, + GtkWidget *to, GdkDevice *device, - GdkCrossingMode mode) + GdkCrossingMode mode) { GdkSurface *from_surface = NULL, *to_surface = NULL; GtkCrossingData crossing; @@ -8283,11 +8310,6 @@ gtk_widget_accessible_interface_init (GtkAccessibleInterface *iface) iface->get_platform_state = gtk_widget_accessible_get_platform_state; } -/* - * GtkBuildable implementation - */ -static GQuark quark_builder_set_id = 0; - static void gtk_widget_buildable_add_child (GtkBuildable *buildable, GtkBuilder *builder, @@ -8330,7 +8352,7 @@ gtk_widget_buildable_interface_init (GtkBuildableIface *iface) static void gtk_widget_buildable_set_id (GtkBuildable *buildable, - const char *id) + const char *id) { g_object_set_qdata_full (G_OBJECT (buildable), quark_builder_set_id, g_strdup (id), g_free); @@ -8344,8 +8366,8 @@ gtk_widget_buildable_get_id (GtkBuildable *buildable) static GObject * gtk_widget_buildable_get_internal_child (GtkBuildable *buildable, - GtkBuilder *builder, - const char *childname) + GtkBuilder *builder, + const char *childname) { GtkWidgetClass *class; GSList *l; @@ -8361,15 +8383,15 @@ gtk_widget_buildable_get_internal_child (GtkBuildable *buildable, GtkWidgetTemplate *template = class->priv->template; if (!template) - continue; + continue; for (l = template->children; l && internal_child_type == 0; l = l->next) - { - AutomaticChildClass *child_class = l->data; + { + AutomaticChildClass *child_class = l->data; - if (child_class->internal_child && strcmp (childname, child_class->name) == 0) - internal_child_type = G_OBJECT_CLASS_TYPE (class); - } + if (child_class->internal_child && strcmp (childname, child_class->name) == 0) + internal_child_type = G_OBJECT_CLASS_TYPE (class); + } } /* Now return the 'internal-child' from the class which declared it, note @@ -8384,7 +8406,7 @@ gtk_widget_buildable_get_internal_child (GtkBuildable *buildable, static void gtk_widget_buildable_parser_finished (GtkBuildable *buildable, - GtkBuilder *builder) + GtkBuilder *builder) { } @@ -9075,26 +9097,6 @@ gtk_widget_buildable_custom_finished (GtkBuildable *buildable, } } -static GtkSizeRequestMode -gtk_widget_real_get_request_mode (GtkWidget *widget) -{ - /* By default widgets don't trade size at all. */ - return GTK_SIZE_REQUEST_CONSTANT_SIZE; -} - -static void -gtk_widget_real_measure (GtkWidget *widget, - GtkOrientation orientation, - int for_size, - int *minimum, - int *natural, - int *minimum_baseline, - int *natural_baseline) -{ - *minimum = 0; - *natural = 0; -} - /** * gtk_widget_get_halign: * @widget: a #GtkWidget @@ -9388,7 +9390,7 @@ gtk_widget_get_clipboard (GtkWidget *widget) * gtk_widget_get_primary_clipboard: * @widget: a #GtkWidget * - * This is a utility function to get the primary clipboard object + * This is a utility function to get the primary clipboard object * for the #GdkDisplay that @widget is using. * * Note that this function always works, even when @widget is not @@ -9464,7 +9466,7 @@ gtk_widget_add_mnemonic_label (GtkWidget *widget, new_list = g_slist_prepend (old_list, label); g_object_set_qdata_full (G_OBJECT (widget), quark_mnemonic_labels, - new_list, (GDestroyNotify) g_slist_free); + new_list, (GDestroyNotify) g_slist_free); /* The ATContext takes ownership of the GList returned by list_mnemonic_labels(), * so we don't need to free it @@ -9500,7 +9502,7 @@ gtk_widget_remove_mnemonic_label (GtkWidget *widget, if (new_list) g_object_set_qdata_full (G_OBJECT (widget), quark_mnemonic_labels, - new_list, (GDestroyNotify) g_slist_free); + new_list, (GDestroyNotify) g_slist_free); if (new_list != NULL && new_list->data != NULL) { @@ -10415,7 +10417,7 @@ gtk_widget_ensure_resize (GtkWidget *widget) void _gtk_widget_add_sizegroup (GtkWidget *widget, - gpointer group) + gpointer group) { GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget); GSList *groups; @@ -10429,7 +10431,7 @@ _gtk_widget_add_sizegroup (GtkWidget *widget, void _gtk_widget_remove_sizegroup (GtkWidget *widget, - gpointer group) + gpointer group) { GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget); GSList *groups; @@ -10477,12 +10479,6 @@ gtk_widget_class_set_css_name (GtkWidgetClass *widget_class, priv->css_name = g_quark_from_string (name); } -static gboolean -gtk_widget_class_get_visible_by_default (GtkWidgetClass *widget_class) -{ - return !g_type_is_a (G_TYPE_FROM_CLASS (widget_class), GTK_TYPE_NATIVE); -} - /** * gtk_widget_class_get_css_name: * @widget_class: class to set the name on @@ -10698,34 +10694,10 @@ template_child_class_new (const char *name, return child_class; } -static void -template_child_class_free (AutomaticChildClass *child_class) -{ - if (child_class) - { - g_free (child_class->name); - g_slice_free (AutomaticChildClass, child_class); - } -} - -static void -template_data_free (GtkWidgetTemplate *template_data) -{ - if (template_data) - { - g_bytes_unref (template_data->data); - g_slist_free_full (template_data->children, (GDestroyNotify)template_child_class_free); - - g_object_unref (template_data->scope); - - g_slice_free (GtkWidgetTemplate, template_data); - } -} - static GHashTable * get_auto_child_hash (GtkWidget *widget, - GType type, - gboolean create) + GType type, + gboolean create) { GHashTable *auto_children; GHashTable *auto_child_hash; @@ -10738,7 +10710,7 @@ get_auto_child_hash (GtkWidget *widget, auto_children = g_hash_table_new_full (g_direct_hash, NULL, - NULL, (GDestroyNotify)g_hash_table_destroy); + NULL, (GDestroyNotify)g_hash_table_destroy); g_object_set_qdata_full (G_OBJECT (widget), quark_auto_children, auto_children, @@ -10751,55 +10723,18 @@ get_auto_child_hash (GtkWidget *widget, if (!auto_child_hash && create) { auto_child_hash = g_hash_table_new_full (g_str_hash, - g_str_equal, - NULL, - (GDestroyNotify)g_object_unref); + g_str_equal, + NULL, + (GDestroyNotify)g_object_unref); g_hash_table_insert (auto_children, - GSIZE_TO_POINTER (type), - auto_child_hash); + GSIZE_TO_POINTER (type), + auto_child_hash); } return auto_child_hash; } -static gboolean -setup_template_child (GtkWidgetTemplate *template_data, - GType class_type, - AutomaticChildClass *child_class, - GtkWidget *widget, - GtkBuilder *builder) -{ - GHashTable *auto_child_hash; - GObject *object; - - object = gtk_builder_get_object (builder, child_class->name); - if (!object) - { - g_critical ("Unable to retrieve object '%s' from class template for type '%s' while building a '%s'", - child_class->name, g_type_name (class_type), G_OBJECT_TYPE_NAME (widget)); - return FALSE; - } - - /* Insert into the hash so that it can be fetched with - * gtk_widget_get_template_child() and also in automated - * implementations of GtkBuildable.get_internal_child() - */ - auto_child_hash = get_auto_child_hash (widget, class_type, TRUE); - g_hash_table_insert (auto_child_hash, child_class->name, g_object_ref (object)); - - if (child_class->offset != 0) - { - gpointer field_p; - - /* Assign 'object' to the specified offset in the instance (or private) data */ - field_p = G_STRUCT_MEMBER_P (widget, child_class->offset); - (* (gpointer *) field_p) = object; - } - - return TRUE; -} - /** * gtk_widget_init_template: * @widget: a #GtkWidget @@ -10844,56 +10779,69 @@ gtk_widget_init_template (GtkWidget *widget) if (template->scope) gtk_builder_set_scope (builder, template->scope); - gtk_builder_set_current_object (builder, G_OBJECT (widget)); + gtk_builder_set_current_object (builder, object); /* This will build the template XML as children to the widget instance, also it * will validate that the template is created for the correct GType and assert that * there is no infinite recursion. */ - if (!gtk_builder_extend_with_template (builder, G_OBJECT (widget), class_type, - (const char *)g_bytes_get_data (template->data, NULL), - g_bytes_get_size (template->data), - &error)) + if (!gtk_builder_extend_with_template (builder, object, class_type, + (const char *)g_bytes_get_data (template->data, NULL), + g_bytes_get_size (template->data), + &error)) { - g_critical ("Error building template class '%s' for an instance of type '%s': %s", - g_type_name (class_type), G_OBJECT_TYPE_NAME (object), error->message); - g_error_free (error); - /* This should never happen, if the template XML cannot be built * then it is a critical programming error. */ - g_object_unref (builder); - return; + g_critical ("Error building template class '%s' for an instance of type '%s': %s", + g_type_name (class_type), G_OBJECT_TYPE_NAME (object), error->message); + g_error_free (error); + goto out; } - /* Build the automatic child data - */ + /* Build the automatic child data */ for (l = template->children; l; l = l->next) { AutomaticChildClass *child_class = l->data; + GHashTable *auto_child_hash; + GObject *child; /* This will setup the pointer of an automated child, and cause * it to be available in any GtkBuildable.get_internal_child() - * invocations which may follow by reference in child classes. - */ - if (!setup_template_child (template, - class_type, - child_class, - widget, - builder)) - { - g_object_unref (builder); - return; - } + * invocations which may follow by reference in child classes. */ + child = gtk_builder_get_object (builder, child_class->name); + if (!child) + { + g_critical ("Unable to retrieve child object '%s' from class " + "template for type '%s' while building a '%s'", + child_class->name, g_type_name (class_type), G_OBJECT_TYPE_NAME (widget)); + goto out; + } + + /* Insert into the hash so that it can be fetched with + * gtk_widget_get_template_child() and also in automated + * implementations of GtkBuildable.get_internal_child() */ + auto_child_hash = get_auto_child_hash (widget, class_type, TRUE); + g_hash_table_insert (auto_child_hash, child_class->name, g_object_ref (child)); + + if (child_class->offset != 0) + { + gpointer field_p; + + /* Assign 'object' to the specified offset in the instance (or private) data */ + field_p = G_STRUCT_MEMBER_P (widget, child_class->offset); + (* (gpointer *) field_p) = child; + } } +out: g_object_unref (builder); } /** * gtk_widget_class_set_template: * @widget_class: A #GtkWidgetClass - * @template_bytes: A #GBytes holding the #GtkBuilder XML + * @template_bytes: A #GBytes holding the #GtkBuilder XML * * This should be called at class initialization time to specify * the GtkBuilder XML to be used to extend a widget. @@ -10904,35 +10852,36 @@ gtk_widget_init_template (GtkWidget *widget) * in the widget’s instance initializer. */ void -gtk_widget_class_set_template (GtkWidgetClass *widget_class, - GBytes *template_bytes) +gtk_widget_class_set_template (GtkWidgetClass *widget_class, + GBytes *template_bytes) { + GError *error = NULL; GBytes *data = NULL; + gconstpointer bytes_data; + gsize bytes_size; g_return_if_fail (GTK_IS_WIDGET_CLASS (widget_class)); g_return_if_fail (widget_class->priv->template == NULL); g_return_if_fail (template_bytes != NULL); widget_class->priv->template = g_slice_new0 (GtkWidgetTemplate); + bytes_data = g_bytes_get_data (template_bytes, &bytes_size); - if (!_gtk_buildable_parser_is_precompiled (g_bytes_get_data (template_bytes, NULL), g_bytes_get_size (template_bytes))) + if (_gtk_buildable_parser_is_precompiled (bytes_data, bytes_size)) { - GError *error = NULL; + widget_class->priv->template->data = g_bytes_ref (template_bytes); + return; + } - data = _gtk_buildable_parser_precompile (g_bytes_get_data (template_bytes, NULL), - g_bytes_get_size (template_bytes), - &error); - if (data == NULL) - { - g_warning ("Failed to precompile template for class %s: %s", G_OBJECT_CLASS_NAME (widget_class), error->message); - g_error_free (error); - } + data = _gtk_buildable_parser_precompile (bytes_data, bytes_size, &error); + if (data == NULL) + { + g_warning ("Failed to precompile template for class %s: %s", G_OBJECT_CLASS_NAME (widget_class), error->message); + g_error_free (error); + return; } - if (data) - widget_class->priv->template->data = data; - else - widget_class->priv->template->data = g_bytes_ref (template_bytes); + widget_class->priv->template->data = data; } /** @@ -10947,7 +10896,7 @@ gtk_widget_class_set_template (GtkWidgetClass *widget_class, */ void gtk_widget_class_set_template_from_resource (GtkWidgetClass *widget_class, - const char *resource_name) + const char *resource_name) { GError *error = NULL; GBytes *bytes = NULL; @@ -10967,7 +10916,7 @@ gtk_widget_class_set_template_from_resource (GtkWidgetClass *widget_class, if (!bytes) { g_critical ("Unable to load resource for composite template for type '%s': %s", - G_OBJECT_CLASS_NAME (widget_class), error->message); + G_OBJECT_CLASS_NAME (widget_class), error->message); g_error_free (error); return; } @@ -11031,7 +10980,7 @@ gtk_widget_class_bind_template_callback_full (GtkWidgetClass *widget_class, */ void gtk_widget_class_set_template_scope (GtkWidgetClass *widget_class, - GtkBuilderScope *scope) + GtkBuilderScope *scope) { g_return_if_fail (GTK_IS_WIDGET_CLASS (widget_class)); g_return_if_fail (widget_class->priv->template != NULL); @@ -11566,12 +11515,12 @@ gtk_widget_child_observer_destroyed (gpointer widget) * gtk_widget_observe_children: * @widget: a #GtkWidget * - * Returns a #GListModel to track the children of @widget. + * Returns a #GListModel to track the children of @widget. * * Calling this function will enable extra internal bookkeeping to track * children and emit signals on the returned listmodel. It may slow down * operations a lot. - * + * * Applications should try hard to avoid calling this function because of * the slowdowns. * @@ -11638,12 +11587,12 @@ gtk_widget_controller_list_get_item (gpointer item, * gtk_widget_observe_controllers: * @widget: a #GtkWidget * - * Returns a #GListModel to track the #GtkEventControllers of @widget. + * Returns a #GListModel to track the #GtkEventControllers of @widget. * * Calling this function will enable extra internal bookkeeping to track * controllers and emit signals on the returned listmodel. It may slow down * operations a lot. - * + * * Applications should try hard to avoid calling this function because of * the slowdowns. * @@ -12077,9 +12026,9 @@ gtk_widget_set_can_target (GtkWidget *widget, /** * gtk_widget_get_can_target: * @widget: a #GtkWidget - * + * * Queries whether @widget can be the target of pointer events. - * + * * Returns: %TRUE if @widget can receive pointer events */ gboolean @@ -12682,50 +12631,6 @@ gtk_widget_update_orientation (GtkWidget *widget, -1); } -static void -gtk_widget_set_accessible_role (GtkWidget *self, - GtkAccessibleRole role) -{ - GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self); - - if (priv->at_context == NULL || !gtk_at_context_is_realized (priv->at_context)) - { - priv->accessible_role = role; - - if (priv->at_context != NULL) - gtk_at_context_set_accessible_role (priv->at_context, role); - - g_object_notify (G_OBJECT (self), "accessible-role"); - } - else - { - char *role_str = g_enum_to_string (GTK_TYPE_ACCESSIBLE_ROLE, priv->accessible_role); - - g_critical ("Widget of type “%s” already has an accessible role of type “%s”", - G_OBJECT_TYPE_NAME (self), - role_str); - g_free (role_str); - } -} - -static GtkAccessibleRole -gtk_widget_get_accessible_role (GtkWidget *self) -{ - GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self); - GtkATContext *context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (self)); - GtkWidgetClassPrivate *class_priv; - - if (context != NULL && gtk_at_context_is_realized (context)) - return gtk_at_context_get_accessible_role (context); - - if (priv->accessible_role != GTK_ACCESSIBLE_ROLE_WIDGET) - return priv->accessible_role; - - class_priv = GTK_WIDGET_GET_CLASS (self)->priv; - - return class_priv->accessible_role; -} - /** * gtk_widget_class_set_accessible_role: * @widget_class: a #GtkWidgetClass |