From 1d7476a7257e9c41e5649160859ba98247af92d9 Mon Sep 17 00:00:00 2001 From: "Owen W. Taylor" Date: Thu, 20 Aug 2009 15:54:11 -0400 Subject: [PATCH] Allow a theme to specify ellipsize width for a title It's nice to indicate when a title is truncated with an ellipsis. Because themes may draw a title multiple times to draw a shadow, or may include the window icon within the title area, we can't determine the proper ellipsization width automatically, so add an optional attribute to the element "ellipsize_width" which, if set, is the width to ellipsize at. This is only enabled if a theme version of 3.1 is required. When it's not set, we keep the old behavior of just letting the title be clipped with a hard edge. https://bugzilla.gnome.org/show_bug.cgi?id=591842 --- doc/theme-format.txt | 4 ++++ src/ui/frames.c | 1 + src/ui/theme-parser.c | 14 +++++++++++++ src/ui/theme.c | 48 +++++++++++++++++++++++++++++++++++++++---- src/ui/theme.h | 1 + 5 files changed, 64 insertions(+), 4 deletions(-) diff --git a/doc/theme-format.txt b/doc/theme-format.txt index cefc31627..b23e6acdb 100644 --- a/doc/theme-format.txt +++ b/doc/theme-format.txt @@ -32,6 +32,10 @@ Additional predefined variables are added for positioning expressions: frame_y_center: the Y center of the entire frame, with respect to the piece currently being drawn. +The <title/> element now supports an "ellipsize_width" attribute. When +specified, this gives a width at which to ellipsize the title. If not +specified, the title will simply be clipped to the title area. + New Features in Theme Format Version 3 ====================================== diff --git a/src/ui/frames.c b/src/ui/frames.c index 01e5027c2..631688270 100644 --- a/src/ui/frames.c +++ b/src/ui/frames.c @@ -501,6 +501,7 @@ meta_frames_ensure_layout (MetaFrames *frames, frame->layout = gtk_widget_create_pango_layout (widget, frame->title); + pango_layout_set_ellipsize (frame->layout, PANGO_ELLIPSIZE_END); pango_layout_set_auto_dir (frame->layout, FALSE); font_desc = meta_gtk_widget_get_font_desc (widget, scale, diff --git a/src/ui/theme-parser.c b/src/ui/theme-parser.c index b2d8bf77d..2d18eff8b 100644 --- a/src/ui/theme-parser.c +++ b/src/ui/theme-parser.c @@ -2584,12 +2584,14 @@ parse_draw_op_element (GMarkupParseContext *context, const char *color; const char *x; const char *y; + const char *ellipsize_width; MetaColorSpec *color_spec; if (!locate_attributes (context, element_name, attribute_names, attribute_values, error, "!color", &color, "!x", &x, "!y", &y, + "ellipsize_width", &ellipsize_width, NULL)) return; @@ -2599,8 +2601,18 @@ parse_draw_op_element (GMarkupParseContext *context, if (!check_expression (y, FALSE, info->theme, context, error)) return; + + if (!check_expression (ellipsize_width, FALSE, info->theme, context, error)) + return; #endif + if (ellipsize_width && peek_required_version (info) < 3001) + { + set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, + ATTRIBUTE_NOT_FOUND, "ellipsize_width", element_name); + return; + } + /* Check last so we don't have to free it when other * stuff fails */ @@ -2617,6 +2629,8 @@ parse_draw_op_element (GMarkupParseContext *context, op->data.title.x = meta_draw_spec_new (info->theme, x, NULL); op->data.title.y = meta_draw_spec_new (info->theme, y, NULL); + if (ellipsize_width) + op->data.title.ellipsize_width = meta_draw_spec_new (info->theme, ellipsize_width, NULL); g_assert (info->op_list); diff --git a/src/ui/theme.c b/src/ui/theme.c index 367423371..cc8ec1b5e 100644 --- a/src/ui/theme.c +++ b/src/ui/theme.c @@ -2884,6 +2884,8 @@ meta_draw_op_free (MetaDrawOp *op) meta_draw_spec_free (op->data.title.x); meta_draw_spec_free (op->data.title.y); + if (op->data.title.ellipsize_width) + meta_draw_spec_free (op->data.title.ellipsize_width); break; case META_DRAW_OP_LIST: @@ -3756,6 +3758,7 @@ meta_draw_op_draw_with_env (const MetaDrawOp *op, if (info->title_layout) { int rx, ry; + PangoRectangle ink_rect, logical_rect; gc = get_gc_for_primitive (widget, drawable, op->data.title.color_spec, @@ -3764,10 +3767,47 @@ meta_draw_op_draw_with_env (const MetaDrawOp *op, rx = parse_x_position_unchecked (op->data.title.x, env); ry = parse_y_position_unchecked (op->data.title.y, env); + if (op->data.title.ellipsize_width) + { + int ellipsize_width; + int right_bearing; + + ellipsize_width = parse_x_position_unchecked (op->data.title.ellipsize_width, env); + /* HACK: parse_x_position_unchecked adds in env->rect.x, subtract out again */ + ellipsize_width -= env->rect.x; + + pango_layout_set_width (info->title_layout, -1); + pango_layout_get_pixel_extents (info->title_layout, + &ink_rect, &logical_rect); + + /* Pango's idea of ellipsization is with respect to the logical rect. + * correct for this, by reducing the ellipsization width by the overflow + * of the un-ellipsized text on the right... it's always the visual + * right we want regardless of bidi, since since the X we pass in to + * gdk_draw_layout() is always the left edge of the line. + */ + right_bearing = (ink_rect.x + ink_rect.width) - (logical_rect.x + logical_rect.width); + right_bearing = MAX (right_bearing, 0); + + ellipsize_width -= right_bearing; + ellipsize_width = MAX (ellipsize_width, 0); + + /* Only ellipsizing when necessary is a performance optimization - + * pango_layout_set_width() will force a relayout if it isn't the + * same as the current width of -1. + */ + if (ellipsize_width < logical_rect.width) + pango_layout_set_width (info->title_layout, PANGO_SCALE * ellipsize_width); + } + gdk_draw_layout (drawable, gc, rx, ry, info->title_layout); + /* Remove any ellipsization we might have set; will short-circuit + * if the width is already -1 */ + pango_layout_set_width (info->title_layout, -1); + g_object_unref (G_OBJECT (gc)); } break; @@ -4326,7 +4366,7 @@ meta_frame_style_draw_with_style (MetaFrameStyle *style, GdkRectangle bottom_titlebar_edge; GdkRectangle top_titlebar_edge; GdkRectangle left_edge, right_edge, bottom_edge; - PangoRectangle extents; + PangoRectangle logical_rect; MetaDrawInfo draw_info; g_return_if_fail (style_gtk->colormap == gdk_drawable_get_colormap (drawable)); @@ -4373,13 +4413,13 @@ meta_frame_style_draw_with_style (MetaFrameStyle *style, if (title_layout) pango_layout_get_pixel_extents (title_layout, - NULL, &extents); + NULL, &logical_rect); draw_info.mini_icon = mini_icon; draw_info.icon = icon; draw_info.title_layout = title_layout; - draw_info.title_layout_width = title_layout ? extents.width : 0; - draw_info.title_layout_height = title_layout ? extents.height : 0; + draw_info.title_layout_width = title_layout ? logical_rect.width : 0; + draw_info.title_layout_height = title_layout ? logical_rect.height : 0; draw_info.fgeom = fgeom; /* The enum is in the order the pieces should be rendered. */ diff --git a/src/ui/theme.h b/src/ui/theme.h index 02a61566a..e9369b15b 100644 --- a/src/ui/theme.h +++ b/src/ui/theme.h @@ -534,6 +534,7 @@ struct _MetaDrawOp MetaColorSpec *color_spec; MetaDrawSpec *x; MetaDrawSpec *y; + MetaDrawSpec *ellipsize_width; } title; struct {