/*
* xfdesktop - xfce4 ' s desktop manager
*
* Copyright ( c ) 2022 Brian Tarricone , < brian @ tarricone . org >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program 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 Library General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <gtk/gtk-a11y.h>
#include <libxfce4util/libxfce4util.h>
#include "xfdesktop-cell-renderer-icon-label.h"
#define DEFAULT_ALIGNMENT PANGO_ALIGN_LEFT
#define DEFAULT_ALIGN_SET FALSE
#define DEFAULT_ELLIPSIZE PANGO_ELLIPSIZE_NONE
#define DEFAULT_ELLIPSIZE_SET FALSE
#define DEFAULT_SIZE_POINTS 8
#define DEFAULT_SIZE_POINTS_SET FALSE
#define DEFAULT_SIZE (DEFAULT_SIZE_POINTS * PANGO_SCALE)
#define DEFAULT_SIZE_SET FALSE
#define DEFAULT_UNDERLINE_WHEN_PRELIT FALSE
#define DEFAULT_UNSELECTED_HEIGHT (-1 )
#define DEFAULT_UNSELECTED_WIDTH (-1 )
#define DEFAULT_WRAP_MODE PANGO_WRAP_WORD
#define DEFAULT_WRAP_WIDTH (-1 )
struct _XfdesktopCellRendererIconLabel
{
GtkCellRenderer parent;
PangoAlignment alignment;
PangoEllipsizeMode ellipsize;
PangoAttrList *extra_attrs;
gint size;
gdouble size_points;
gchar *text;
gint unselected_width;
gint unselected_height;
PangoWrapMode wrap_mode;
gint wrap_width;
guint align_set: 1 ;
guint ellipsize_set: 1 ;
guint size_set: 1 ;
guint size_points_set: 1 ;
guint underline_when_prelit: 1 ;
};
struct _XfdesktopCellRendererIconLabelClass
{
GtkCellRendererClass parent_class;
};
enum
{
PROP0 = 0 ,
PROP_ALIGNMENT,
PROP_ALIGN_SET,
PROP_ATTRIBUTES,
PROP_ELLIPSIZE,
PROP_ELLIPSIZE_SET,
PROP_SIZE,
PROP_SIZE_SET,
PROP_SIZE_POINTS,
PROP_SIZE_POINTS_SET,
PROP_TEXT,
PROP_UNDERLINE_WHEN_PRELIT,
PROP_UNSELECTED_HEIGHT,
PROP_UNSELECTED_WIDTH,
PROP_WRAP_MODE,
PROP_WRAP_WIDTH,
N_PROPS,
};
static void xfdesktop_cell_renderer_icon_label_set_property(GObject *obj,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void xfdesktop_cell_renderer_icon_label_get_property(GObject *obj,
guint prop_id,
GValue *value,
GParamSpec *pspec);
static void xfdesktop_cell_renderer_icon_label_finalize(GObject *obj);
static void xfdesktop_cell_renderer_icon_label_render(GtkCellRenderer *cell,
cairo_t *cr,
GtkWidget *widget,
const GdkRectangle *background_area,
const GdkRectangle *cell_area,
GtkCellRendererState flags);
static void xfdesktop_cell_renderer_icon_label_get_preferred_width(GtkCellRenderer *cell,
GtkWidget *widget,
gint *minimal_size,
gint *natural_size);
static void xfdesktop_cell_renderer_icon_label_get_preferred_height(GtkCellRenderer *cell,
GtkWidget *widget,
gint *minimal_size,
gint *natural_size);
static void xfdesktop_cell_renderer_icon_label_get_preferred_height_for_width(GtkCellRenderer *cell,
GtkWidget *widget,
gint width,
gint *minimum_height,
gint *natural_height);
static void xfdesktop_cell_renderer_icon_label_get_preferred_width_for_height(GtkCellRenderer *cell,
GtkWidget *widget,
gint height,
gint *minimum_width,
gint *natural_width);
static void xfdesktop_cell_renderer_icon_label_get_aligned_area(GtkCellRenderer *cell,
GtkWidget *widget,
GtkCellRendererState flags,
const GdkRectangle *cell_area,
GdkRectangle *aligned_area);
static void get_size(XfdesktopCellRendererIconLabel *renderer,
GtkWidget *widget,
const GdkRectangle *cell_area,
PangoLayout *layout,
GdkRectangle *area);
static PangoLayout *create_layout(XfdesktopCellRendererIconLabel *renderer,
GtkWidget *widget,
const GdkRectangle *cell_area,
GtkCellRendererState flags);
G_DEFINE_TYPE(XfdesktopCellRendererIconLabel, xfdesktop_cell_renderer_icon_label, GTK_TYPE_CELL_RENDERER)
static GParamSpec *obj_properties[N_PROPS] = { NULL, };
static void
xfdesktop_cell_renderer_icon_label_class_init(XfdesktopCellRendererIconLabelClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
GtkCellRendererClass *renderer_class = GTK_CELL_RENDERER_CLASS(klass);
gobject_class->set_property = xfdesktop_cell_renderer_icon_label_set_property;
gobject_class->get_property = xfdesktop_cell_renderer_icon_label_get_property;
gobject_class->finalize = xfdesktop_cell_renderer_icon_label_finalize;
renderer_class->render = xfdesktop_cell_renderer_icon_label_render;
renderer_class->get_preferred_width = xfdesktop_cell_renderer_icon_label_get_preferred_width;
renderer_class->get_preferred_height = xfdesktop_cell_renderer_icon_label_get_preferred_height;
renderer_class->get_preferred_height_for_width = xfdesktop_cell_renderer_icon_label_get_preferred_height_for_width;
renderer_class->get_preferred_width_for_height = xfdesktop_cell_renderer_icon_label_get_preferred_width_for_height;
renderer_class->get_aligned_area = xfdesktop_cell_renderer_icon_label_get_aligned_area;
#define PARAM_FLAGS (G_PARAM_READWRITE \
| G_PARAM_STATIC_NAME \
| G_PARAM_STATIC_NICK \
| G_PARAM_STATIC_BLURB)
obj_properties[PROP_ALIGNMENT] =
g_param_spec_enum("alignment" ,
"alignment" ,
"horizontal text alignment in cell" ,
PANGO_TYPE_ALIGNMENT,
DEFAULT_ALIGNMENT,
PARAM_FLAGS);
obj_properties[PROP_ATTRIBUTES] =
g_param_spec_boxed("attributes" ,
"attributes" ,
"extra pango attributes to set" ,
PANGO_TYPE_ATTR_LIST,
PARAM_FLAGS);
obj_properties[PROP_ELLIPSIZE] =
g_param_spec_enum("ellipsize" ,
"ellipsize" ,
"how to ellipsize when the text is too large for the cell area" ,
PANGO_TYPE_ELLIPSIZE_MODE,
DEFAULT_ELLIPSIZE,
PARAM_FLAGS);
obj_properties[PROP_SIZE] =
g_param_spec_int("size" ,
"size" ,
"font size in pango units" ,
1 , G_MAXINT, DEFAULT_SIZE,
PARAM_FLAGS);
obj_properties[PROP_SIZE_POINTS] =
g_param_spec_double("size-points" ,
"size-points" ,
"font size in points" ,
2 , G_MAXINT, DEFAULT_SIZE_POINTS,
PARAM_FLAGS);
obj_properties[PROP_TEXT] =
g_param_spec_string("text" ,
"text" ,
"text to display in the cell" ,
NULL,
PARAM_FLAGS);
obj_properties[PROP_UNSELECTED_HEIGHT] =
g_param_spec_int("unselected-height" ,
"unselected-height" ,
"constrained height when item is not selected and mode is height-for-width" ,
-1 , G_MAXINT, DEFAULT_UNSELECTED_HEIGHT,
PARAM_FLAGS);
obj_properties[PROP_UNSELECTED_WIDTH] =
g_param_spec_int("unselected-width" ,
"unselected-width" ,
"constrained width when item is not selected and mode is width-for-height" ,
-1 , G_MAXINT, DEFAULT_UNSELECTED_HEIGHT,
PARAM_FLAGS);
obj_properties[PROP_WRAP_MODE] =
g_param_spec_enum("wrap-mode" ,
"wrap-mode" ,
"mode for text line wrapping" ,
PANGO_TYPE_WRAP_MODE,
DEFAULT_WRAP_MODE,
PARAM_FLAGS);
obj_properties[PROP_WRAP_WIDTH] =
g_param_spec_int("wrap-width" ,
"wrap-width" ,
"width to wrap text in pango units" ,
-1 , G_MAXINT, DEFAULT_WRAP_WIDTH,
PARAM_FLAGS);
#define DEFINE_BOOL_PROP(prop_id, name, blurb, default_val) G_STMT_START{ \
obj_properties[prop_id] = g_param_spec_boolean(name, name, blurb, default_val, PARAM_FLAGS); \
}G_STMT_END
DEFINE_BOOL_PROP(PROP_ALIGN_SET, "align-set" , "whether or not the 'alignment' property should be used" , DEFAULT_ALIGN_SET);
DEFINE_BOOL_PROP(PROP_ELLIPSIZE_SET, "ellipsize-set" , "whether or not the 'ellipsize' property should be used" , DEFAULT_ELLIPSIZE_SET);
DEFINE_BOOL_PROP(PROP_SIZE_SET, "size-set" , "whether or not the 'size' property should be used" , DEFAULT_SIZE_SET);
DEFINE_BOOL_PROP(PROP_SIZE_POINTS_SET, "size-points-set" , "whether or not the 'size-points' property should be used" , DEFAULT_SIZE_POINTS_SET);
DEFINE_BOOL_PROP(PROP_UNDERLINE_WHEN_PRELIT, "underline-when-prelit" , "whether or not to underline text when the PRELIT flag is set" , DEFAULT_UNDERLINE_WHEN_PRELIT);
#undef DEFINE_SETTER
#undef PARAM_FLAGS
g_object_class_install_properties(gobject_class, G_N_ELEMENTS(obj_properties), obj_properties);
gtk_cell_renderer_class_set_accessible_type(renderer_class, GTK_TYPE_TEXT_CELL_ACCESSIBLE);
}
static void
xfdesktop_cell_renderer_icon_label_init(XfdesktopCellRendererIconLabel *renderer)
{
renderer->alignment = DEFAULT_ALIGNMENT;
renderer->align_set = DEFAULT_ALIGN_SET;
renderer->ellipsize = DEFAULT_ELLIPSIZE;
renderer->ellipsize_set = DEFAULT_ELLIPSIZE_SET;
renderer->extra_attrs = NULL;
renderer->size = DEFAULT_SIZE;
renderer->size_set = DEFAULT_SIZE_SET;
renderer->text = NULL;
renderer->unselected_height = DEFAULT_UNSELECTED_HEIGHT;
renderer->unselected_width = DEFAULT_UNSELECTED_WIDTH;
renderer->wrap_mode = DEFAULT_WRAP_MODE;
renderer->wrap_width = DEFAULT_WRAP_WIDTH;
}
static void
xfdesktop_cell_renderer_icon_label_set_property(GObject *obj,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
XfdesktopCellRendererIconLabel *renderer = XFDESKTOP_CELL_RENDERER_ICON_LABEL(obj);
switch (prop_id) {
case PROP_ALIGNMENT:
renderer->alignment = g_value_get_enum(value);
break ;
case PROP_ALIGN_SET:
renderer->align_set = g_value_get_boolean(value);
break ;
case PROP_ATTRIBUTES:
if (renderer->extra_attrs != NULL) {
pango_attr_list_unref(renderer->extra_attrs);
}
renderer->extra_attrs = g_value_dup_boxed(value);
break ;
case PROP_ELLIPSIZE:
renderer->ellipsize = g_value_get_enum(value);
break ;
case PROP_ELLIPSIZE_SET:
renderer->ellipsize_set = g_value_get_boolean(value);
break ;
case PROP_SIZE:
renderer->size = g_value_get_int(value);
break ;
case PROP_SIZE_SET:
renderer->size_set = g_value_get_boolean(value);
break ;
case PROP_SIZE_POINTS:
renderer->size_points = g_value_get_double(value);
break ;
case PROP_SIZE_POINTS_SET:
renderer->size_points_set = g_value_get_boolean(value);
break ;
case PROP_TEXT:
g_free(renderer->text);
renderer->text = g_value_dup_string(value);
break ;
case PROP_UNDERLINE_WHEN_PRELIT:
renderer->underline_when_prelit = g_value_get_boolean(value);
break ;
case PROP_UNSELECTED_HEIGHT:
renderer->unselected_height = g_value_get_int(value);
break ;
case PROP_UNSELECTED_WIDTH:
renderer->unselected_width = g_value_get_int(value);
break ;
case PROP_WRAP_MODE:
renderer->wrap_mode = g_value_get_enum(value);
break ;
case PROP_WRAP_WIDTH:
renderer->wrap_width = g_value_get_int(value);
break ;
default :
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec);
break ;
}
}
static void
xfdesktop_cell_renderer_icon_label_get_property(GObject *obj,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
XfdesktopCellRendererIconLabel *renderer = XFDESKTOP_CELL_RENDERER_ICON_LABEL(obj);
switch (prop_id) {
case PROP_ALIGNMENT:
g_value_set_enum(value, renderer->alignment);
break ;
case PROP_ALIGN_SET:
g_value_set_boolean(value, renderer->align_set);
break ;
case PROP_ATTRIBUTES:
g_value_set_boxed(value, renderer->extra_attrs);
break ;
case PROP_ELLIPSIZE:
g_value_set_enum(value, renderer->ellipsize);
break ;
case PROP_ELLIPSIZE_SET:
g_value_set_boolean(value, renderer->ellipsize_set);
break ;
case PROP_SIZE:
g_value_set_int(value, renderer->size);
break ;
case PROP_SIZE_SET:
g_value_set_boolean(value, renderer->size_set);
break ;
case PROP_SIZE_POINTS:
g_value_set_double(value, renderer->size_points);
break ;
case PROP_SIZE_POINTS_SET:
g_value_set_boolean(value, renderer->size_points_set);
break ;
case PROP_TEXT:
g_value_set_string(value, renderer->text);
break ;
case PROP_UNDERLINE_WHEN_PRELIT:
g_value_set_boolean(value, renderer->underline_when_prelit);
break ;
case PROP_UNSELECTED_HEIGHT:
g_value_set_int(value, renderer->unselected_height);
break ;
case PROP_UNSELECTED_WIDTH:
g_value_set_int(value, renderer->unselected_width);
break ;
case PROP_WRAP_MODE:
g_value_set_enum(value, renderer->wrap_mode);
break ;
case PROP_WRAP_WIDTH:
g_value_set_int(value, renderer->wrap_width);
break ;
default :
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec);
return ;
}
g_object_notify_by_pspec(obj, pspec);
}
static void
xfdesktop_cell_renderer_icon_label_finalize(GObject *obj)
{
XfdesktopCellRendererIconLabel *renderer = XFDESKTOP_CELL_RENDERER_ICON_LABEL(obj);
if (renderer->extra_attrs) {
pango_attr_list_unref(renderer->extra_attrs);
}
g_free(renderer->text);
G_OBJECT_CLASS(xfdesktop_cell_renderer_icon_label_parent_class)->finalize(obj);
}
static void
xfdesktop_cell_renderer_icon_label_render(GtkCellRenderer *cell,
cairo_t *cr,
GtkWidget *widget,
const GdkRectangle *background_area,
const GdkRectangle *cell_area,
GtkCellRendererState flags)
{
XfdesktopCellRendererIconLabel *renderer = XFDESKTOP_CELL_RENDERER_ICON_LABEL(cell);
GtkStyleContext *style_context = gtk_widget_get_style_context(widget);
PangoLayout *layout;
GdkRectangle box_area;
gint xpad, ypad;
PangoRectangle extents;
gint rtl_offset;
gtk_style_context_save(style_context);
gtk_style_context_add_class(style_context, GTK_STYLE_CLASS_LABEL);
gtk_cell_renderer_get_padding(cell, &xpad, &ypad);
layout = create_layout(renderer, widget, cell_area, flags);
get_size(renderer, widget, cell_area, layout, &box_area);
pango_layout_get_pixel_extents(layout, NULL, &extents);
rtl_offset = extents.x;
box_area.x += cell_area->x;
box_area.y += cell_area->y;
#if 0
DBG("style: %s" , gtk_style_context_to_string(style_context, 0 ));
DBG("cell_area: %dx%d+%d+%d" , cell_area->width, cell_area->height, cell_area->x, cell_area->y);
DBG("box_area: %dx%d+%d+%d" , box_area.width, box_area.height, box_area.x, box_area.y);
DBG("text_ext: %dx%d+%d+%d" , box_area.width - xpad * 2 , box_area.height - ypad * 2 , box_area.x + xpad, box_area.y + ypad);
DBG("text loc: +%d+%d" , box_area.x + xpad, box_area.y + ypad);
DBG("text ext: %dx%d+%d+%d" , extents.width, extents.height, extents.x, extents.y);
#endif
gtk_render_background(style_context, cr,
box_area.x, box_area.y,
box_area.width, box_area.height);
gtk_render_frame(style_context, cr,
box_area.x, box_area.y,
box_area.width, box_area.height);
if (flags & GTK_CELL_RENDERER_FOCUSED) {
gtk_render_focus(style_context, cr,
box_area.x, box_area.y,
box_area.width, box_area.height);
}
gtk_render_layout(style_context, cr, box_area.x - rtl_offset + xpad, box_area.y + ypad, layout);
#if 0
cairo_set_source_rgb(cr, 0 .0 , 1 .0 , 0 .0 );
cairo_rectangle(cr, box_area.x + xpad, box_area.y + xpad, box_area.width - xpad * 2 , box_area.height - ypad * 2 );
cairo_stroke(cr);
#endif
gtk_style_context_restore(style_context);
g_object_unref(layout);
}
// Inspired by GtkCellRendererText's implementation
static void
xfdesktop_cell_renderer_icon_label_get_preferred_width(GtkCellRenderer *cell,
GtkWidget *widget,
gint *minimal_size,
gint *natural_size)
{
XfdesktopCellRendererIconLabel *renderer = XFDESKTOP_CELL_RENDERER_ICON_LABEL(cell);
PangoLayout *layout;
PangoRectangle extents;
gint xpad;
gint min_width;
layout = create_layout(renderer, widget, NULL, 0 );
gtk_cell_renderer_get_padding(cell, &xpad, NULL);
pango_layout_set_width(layout, -1 );
pango_layout_get_pixel_extents(layout, NULL, &extents);
if (renderer->ellipsize_set && renderer->ellipsize != PANGO_ELLIPSIZE_NONE) {
const gint ellipsize_chars = 3 ;
PangoContext *context = pango_layout_get_context(layout);
PangoFontMetrics *metrics = pango_context_get_metrics(context,
pango_context_get_font_description(context),
pango_context_get_language(context));
gint char_width = pango_font_metrics_get_approximate_char_width(metrics);
min_width = MIN(extents.width, PANGO_PIXELS(char_width) * ellipsize_chars);
} else if (renderer->wrap_width > 0 ) {
min_width = extents.x + MIN(extents.width, renderer->wrap_width);
} else {
min_width = extents.x + extents.width;
}
min_width += xpad * 2 ;
if (minimal_size != NULL) {
*minimal_size = min_width;
}
if (natural_size != NULL) {
*natural_size = MAX(min_width, extents.width + xpad * 2 );
}
g_object_unref(layout);
}
static void
xfdesktop_cell_renderer_icon_label_get_preferred_height(GtkCellRenderer *cell,
GtkWidget *widget,
gint *minimal_size,
gint *natural_size)
{
XfdesktopCellRendererIconLabel *renderer = XFDESKTOP_CELL_RENDERER_ICON_LABEL(cell);
PangoLayout *layout;
PangoRectangle extents;
gint ypad;
gint min_height, nat_height;
layout = create_layout(renderer, widget, NULL, 0 );
gtk_cell_renderer_get_padding(cell, NULL, &ypad);
pango_layout_get_pixel_extents(layout, NULL, &extents);
nat_height = extents.height + ypad * 2 ;
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE);
pango_layout_set_height(layout, -1 );
pango_layout_get_extents(layout, NULL, &extents);
min_height = extents.height + ypad * 2 ;
if (*minimal_size) {
*minimal_size = min_height;
}
if (*natural_size) {
*natural_size = MAX(min_height, nat_height);
}
g_object_unref(layout);
}
static void
xfdesktop_cell_renderer_icon_label_get_preferred_height_for_width(GtkCellRenderer *cell,
GtkWidget *widget,
gint width,
gint *minimum_height,
gint *natural_height)
{
XfdesktopCellRendererIconLabel *renderer = XFDESKTOP_CELL_RENDERER_ICON_LABEL(cell);
PangoLayout *layout;
gint xpad, ypad;
gint min_height, nat_height;
gtk_cell_renderer_get_padding(cell, &xpad, &ypad);
layout = create_layout(renderer, widget, NULL, 0 );
pango_layout_set_width(layout, (width - xpad * 2 ) * PANGO_SCALE);
pango_layout_get_pixel_size(layout, NULL, &min_height);
pango_layout_set_height(layout, -1 );
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE);
pango_layout_get_pixel_size(layout, NULL, &nat_height);
if (minimum_height != NULL) {
*minimum_height = min_height + ypad * 2 ;
}
if (natural_height != NULL) {
*natural_height = MAX(nat_height, min_height) + ypad * 2 ;
}
g_object_unref(layout);
}
static void
xfdesktop_cell_renderer_icon_label_get_preferred_width_for_height(GtkCellRenderer *cell,
GtkWidget *widget,
gint height,
gint *minimum_width,
gint *natural_width)
{
XfdesktopCellRendererIconLabel *renderer = XFDESKTOP_CELL_RENDERER_ICON_LABEL(cell);
PangoLayout *layout;
gint xpad, ypad;
gint min_width, nat_width;
gtk_cell_renderer_get_padding(cell, &xpad, &ypad);
layout = create_layout(renderer, widget, NULL, 0 );
pango_layout_set_height(layout, (height - ypad * 2 ) * PANGO_SCALE);
pango_layout_get_pixel_size(layout, &min_width, NULL);
pango_layout_set_width(layout, -1 );
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE);
pango_layout_get_pixel_size(layout, &nat_width, NULL);
if (minimum_width != NULL) {
*minimum_width = min_width + ypad * 2 ;
}
if (natural_width != NULL) {
*natural_width = MAX(nat_width, min_width) + ypad * 2 ;
}
g_object_unref(layout);
}
static void
xfdesktop_cell_renderer_icon_label_get_aligned_area(GtkCellRenderer *cell,
GtkWidget *widget,
GtkCellRendererState flags,
const GdkRectangle *cell_area,
GdkRectangle *aligned_area)
{
XfdesktopCellRendererIconLabel *renderer = XFDESKTOP_CELL_RENDERER_ICON_LABEL(cell);
PangoLayout *layout;
layout = create_layout(renderer, widget, cell_area, flags);
get_size(renderer, widget, cell_area, layout, aligned_area);
#if 0
DBG("label area: %dx%d+%d+%d" , aligned_area->width, aligned_area->height, aligned_area->x, aligned_area->y);
#endif
g_object_unref(layout);
}
static void
get_size(XfdesktopCellRendererIconLabel *renderer,
GtkWidget *widget,
const GdkRectangle *cell_area,
PangoLayout *layout,
GdkRectangle *area)
{
PangoRectangle extents;
gint xpad, ypad;
gtk_cell_renderer_get_padding(GTK_CELL_RENDERER(renderer), &xpad, &ypad);
pango_layout_get_pixel_extents(layout, NULL, &extents);
if (cell_area != NULL) {
gfloat xalign, yalign;
gtk_cell_renderer_get_alignment(GTK_CELL_RENDERER(renderer), &xalign, &yalign);
extents.width = MIN(extents.width, cell_area->width - xpad * 2 );
extents.height = MIN(extents.height, cell_area->height - ypad * 2 );
if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL) {
extents.x = (1 .0 - xalign) * (cell_area->width - extents.width - xpad * 2 );
} else {
extents.x = xalign * (cell_area->width - extents.width - xpad * 2 );
}
extents.y = MAX(0 , yalign * (cell_area->height - extents.height - ypad * 2 ));
} else {
extents.x = 0 ;
extents.y = 0 ;
}
area->x = extents.x;
area->y = extents.y;
area->width = extents.width + xpad * 2 ;
area->height = extents.height + ypad * 2 ;
}
static PangoLayout *
create_layout(XfdesktopCellRendererIconLabel *renderer,
GtkWidget *widget,
const GdkRectangle *cell_area,
GtkCellRendererState flags)
{
gboolean is_selected = (flags & GTK_CELL_RENDERER_SELECTED) != 0 ;
PangoLayout *layout;
PangoAttrList *attr_list;
gint xpad, ypad;
gint fixed_width, fixed_height;
gtk_cell_renderer_get_padding(GTK_CELL_RENDERER(renderer), &xpad, &ypad);
gtk_cell_renderer_get_fixed_size(GTK_CELL_RENDERER(renderer), &fixed_width, &fixed_height);
layout = gtk_widget_create_pango_layout(widget, renderer->text);
if (renderer->extra_attrs != NULL) {
attr_list = pango_attr_list_copy(renderer->extra_attrs);
} else {
attr_list = pango_attr_list_new();
}
if (renderer->underline_when_prelit && (flags & GTK_CELL_RENDERER_PRELIT) != 0 ) {
PangoAttribute *uline = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
uline->start_index = 0 ;
uline->end_index = -1 ;
pango_attr_list_change(attr_list, uline);
}
if (renderer->align_set) {
pango_layout_set_alignment(layout, renderer->alignment);
} else {
if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL) {
pango_layout_set_alignment(layout, PANGO_ALIGN_RIGHT);
} else {
pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT);
}
}
if (renderer->ellipsize_set) {
pango_layout_set_ellipsize(layout, renderer->ellipsize);
}
if (renderer->size_set || renderer->size_points_set) {
PangoFontDescription *pfd = pango_context_get_font_description(gtk_widget_get_pango_context(widget));
pfd = pango_font_description_copy(pfd);
if (renderer->size_set) {
pango_font_description_set_size(pfd, renderer->size);
} else if (renderer->size_points_set) {
pango_font_description_set_size(pfd, renderer->size_points * PANGO_SCALE);
}
pango_layout_set_font_description(layout, pfd);
pango_font_description_free(pfd);
}
pango_layout_set_attributes(layout, attr_list);
pango_attr_list_unref(attr_list);
if (renderer->wrap_width == -1 || (is_selected && gtk_cell_renderer_get_request_mode(GTK_CELL_RENDERER(renderer)) == GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT)) {
pango_layout_set_width(layout, -1 );
pango_layout_set_wrap(layout, PANGO_WRAP_CHAR);
} else {
gint width;
PangoRectangle extents;
if (fixed_width < 0 ) {
fixed_width = renderer->unselected_width;
}
if (fixed_width > 0 ) {
pango_layout_set_width(layout, (fixed_width - xpad * 2 ) * PANGO_SCALE);
}
pango_layout_get_extents(layout, NULL, &extents);
if (cell_area != NULL) {
width = MIN((cell_area->width - xpad * 2 ) * PANGO_SCALE, extents.width + xpad * 2 );
} else {
width = MIN(renderer->wrap_width * PANGO_SCALE, extents.width + xpad * 2 );
}
pango_layout_set_width(layout, MIN(extents.width, width));
pango_layout_set_wrap(layout, renderer->wrap_mode);
}
if (is_selected && gtk_cell_renderer_get_request_mode(GTK_CELL_RENDERER(renderer)) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH) {
pango_layout_set_height(layout, -1 );
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE);
} else {
PangoRectangle extents;
if (fixed_height < 0 ) {
fixed_height = renderer->unselected_height;
}
if (fixed_height > 0 ) {
pango_layout_set_height(layout, (fixed_height - ypad * 2 ) * PANGO_SCALE);
}
pango_layout_get_extents(layout, NULL, &extents);
if (cell_area != NULL) {
gint height = (cell_area->height - ypad * 2 ) * PANGO_SCALE;
pango_layout_set_height(layout, MIN(extents.height, height));
} else {
pango_layout_set_height(layout, extents.height);
}
}
return layout;
}
GtkCellRenderer *
xfdesktop_cell_renderer_icon_label_new(void )
{
return g_object_new(XFDESKTOP_TYPE_CELL_RENDERER_ICON_LABEL, NULL);
}
Messung V0.5 in Prozent C=98 H=93 G=95
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-07-10)
¤
*© Formatika GbR, Deutschland