1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <vcl/svapp.hxx>
11 #include "customcellrenderer.hxx"
12 #if !GTK_CHECK_VERSION(4, 0, 0)
13 #include <gtk/gtk-a11y.h>
18 struct _CustomCellRendererClass
: public GtkCellRendererTextClass
25 PROP_INSTANCE_TREE_VIEW
= 10001
29 #if defined __clang__ && GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 68
30 #pragma clang diagnostic push
31 #pragma clang diagnostic ignored "-Wdeprecated-volatile"
33 G_DEFINE_TYPE(CustomCellRenderer
, custom_cell_renderer
, GTK_TYPE_CELL_RENDERER_TEXT
)
34 #if defined __clang__ && GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 68
35 #pragma clang diagnostic pop
38 static void custom_cell_renderer_init(CustomCellRenderer
* self
)
41 SolarMutexGuard aGuard
;
42 new (&self
->device
) VclPtr
<VirtualDevice
>;
45 // prevent loplugin:unreffun firing on macro generated function
46 (void)custom_cell_renderer_get_instance_private(self
);
49 static void custom_cell_renderer_get_property(GObject
* object
, guint param_id
, GValue
* value
,
52 CustomCellRenderer
* cellsurface
= CUSTOM_CELL_RENDERER(object
);
57 g_value_set_string(value
, cellsurface
->id
);
59 case PROP_INSTANCE_TREE_VIEW
:
60 g_value_set_pointer(value
, cellsurface
->instance
);
63 G_OBJECT_CLASS(custom_cell_renderer_parent_class
)
64 ->get_property(object
, param_id
, value
, pspec
);
69 static void custom_cell_renderer_set_property(GObject
* object
, guint param_id
, const GValue
* value
,
72 CustomCellRenderer
* cellsurface
= CUSTOM_CELL_RENDERER(object
);
77 g_free(cellsurface
->id
);
78 cellsurface
->id
= g_value_dup_string(value
);
80 case PROP_INSTANCE_TREE_VIEW
:
81 cellsurface
->instance
= g_value_get_pointer(value
);
84 G_OBJECT_CLASS(custom_cell_renderer_parent_class
)
85 ->set_property(object
, param_id
, value
, pspec
);
90 static bool custom_cell_renderer_get_preferred_size(GtkCellRenderer
* cell
,
91 GtkOrientation orientation
, gint
* minimum_size
,
94 #if GTK_CHECK_VERSION(4, 0, 0)
95 static void custom_cell_renderer_snapshot(GtkCellRenderer
* cell
, GtkSnapshot
* snapshot
,
96 GtkWidget
* widget
, const GdkRectangle
* background_area
,
97 const GdkRectangle
* cell_area
,
98 GtkCellRendererState flags
);
101 static void custom_cell_renderer_render(GtkCellRenderer
* cell
, cairo_t
* cr
, GtkWidget
* widget
,
102 const GdkRectangle
* background_area
,
103 const GdkRectangle
* cell_area
, GtkCellRendererState flags
);
105 static void custom_cell_renderer_finalize(GObject
* object
)
107 CustomCellRenderer
* cellsurface
= CUSTOM_CELL_RENDERER(object
);
109 g_free(cellsurface
->id
);
112 SolarMutexGuard aGuard
;
113 cellsurface
->device
.disposeAndClear();
114 cellsurface
->device
.~VclPtr
<VirtualDevice
>();
117 G_OBJECT_CLASS(custom_cell_renderer_parent_class
)->finalize(object
);
120 static void custom_cell_renderer_get_preferred_width(GtkCellRenderer
* cell
, GtkWidget
* widget
,
121 gint
* minimum_size
, gint
* natural_size
)
123 if (!custom_cell_renderer_get_preferred_size(cell
, GTK_ORIENTATION_HORIZONTAL
, minimum_size
,
126 // fallback to parent if we're empty
127 GTK_CELL_RENDERER_CLASS(custom_cell_renderer_parent_class
)
128 ->get_preferred_width(cell
, widget
, minimum_size
, natural_size
);
132 static void custom_cell_renderer_get_preferred_height(GtkCellRenderer
* cell
, GtkWidget
* widget
,
133 gint
* minimum_size
, gint
* natural_size
)
135 if (!custom_cell_renderer_get_preferred_size(cell
, GTK_ORIENTATION_VERTICAL
, minimum_size
,
138 // fallback to parent if we're empty
139 GTK_CELL_RENDERER_CLASS(custom_cell_renderer_parent_class
)
140 ->get_preferred_height(cell
, widget
, minimum_size
, natural_size
);
144 static void custom_cell_renderer_get_preferred_height_for_width(GtkCellRenderer
* cell
,
145 GtkWidget
* widget
, gint
/*width*/,
146 gint
* minimum_height
,
147 gint
* natural_height
)
149 gtk_cell_renderer_get_preferred_height(cell
, widget
, minimum_height
, natural_height
);
152 static void custom_cell_renderer_get_preferred_width_for_height(GtkCellRenderer
* cell
,
153 GtkWidget
* widget
, gint
/*height*/,
157 gtk_cell_renderer_get_preferred_width(cell
, widget
, minimum_width
, natural_width
);
160 void custom_cell_renderer_class_init(CustomCellRendererClass
* klass
)
162 GtkCellRendererClass
* cell_class
= GTK_CELL_RENDERER_CLASS(klass
);
163 GObjectClass
* object_class
= G_OBJECT_CLASS(klass
);
165 /* Hook up functions to set and get our custom cell renderer properties */
166 object_class
->get_property
= custom_cell_renderer_get_property
;
167 object_class
->set_property
= custom_cell_renderer_set_property
;
169 custom_cell_renderer_parent_class
= g_type_class_peek_parent(klass
);
170 object_class
->finalize
= custom_cell_renderer_finalize
;
172 cell_class
->get_preferred_width
= custom_cell_renderer_get_preferred_width
;
173 cell_class
->get_preferred_height
= custom_cell_renderer_get_preferred_height
;
174 cell_class
->get_preferred_width_for_height
175 = custom_cell_renderer_get_preferred_width_for_height
;
176 cell_class
->get_preferred_height_for_width
177 = custom_cell_renderer_get_preferred_height_for_width
;
179 #if GTK_CHECK_VERSION(4, 0, 0)
180 cell_class
->snapshot
= custom_cell_renderer_snapshot
;
182 cell_class
->render
= custom_cell_renderer_render
;
185 g_object_class_install_property(
186 object_class
, PROP_ID
,
187 g_param_spec_string("id", "ID", "The ID of the custom data", nullptr, G_PARAM_READWRITE
));
189 g_object_class_install_property(
190 object_class
, PROP_INSTANCE_TREE_VIEW
,
191 g_param_spec_pointer("instance", "Instance", "The GtkInstanceTreeView", G_PARAM_READWRITE
));
193 #if !GTK_CHECK_VERSION(4, 0, 0)
194 gtk_cell_renderer_class_set_accessible_type(cell_class
, GTK_TYPE_TEXT_CELL_ACCESSIBLE
);
198 GtkCellRenderer
* custom_cell_renderer_new()
200 return GTK_CELL_RENDERER(g_object_new(CUSTOM_TYPE_CELL_RENDERER
, nullptr));
203 bool custom_cell_renderer_get_preferred_size(GtkCellRenderer
* cell
, GtkOrientation orientation
,
204 gint
* minimum_size
, gint
* natural_size
)
206 GValue value
= G_VALUE_INIT
;
207 g_value_init(&value
, G_TYPE_STRING
);
208 g_object_get_property(G_OBJECT(cell
), "id", &value
);
210 const char* pStr
= g_value_get_string(&value
);
212 OUString
sId(pStr
, pStr
? strlen(pStr
) : 0, RTL_TEXTENCODING_UTF8
);
214 value
= G_VALUE_INIT
;
215 g_value_init(&value
, G_TYPE_POINTER
);
216 g_object_get_property(G_OBJECT(cell
), "instance", &value
);
218 CustomCellRenderer
* cellsurface
= CUSTOM_CELL_RENDERER(cell
);
222 gpointer pWidget
= g_value_get_pointer(&value
);
225 SolarMutexGuard aGuard
;
226 custom_cell_renderer_ensure_device(cellsurface
, pWidget
);
227 aSize
= custom_cell_renderer_get_size(*cellsurface
->device
, sId
, pWidget
);
230 if (orientation
== GTK_ORIENTATION_HORIZONTAL
)
233 *minimum_size
= aSize
.Width();
236 *natural_size
= aSize
.Width();
241 *minimum_size
= aSize
.Height();
244 *natural_size
= aSize
.Height();
250 void custom_cell_renderer_render(GtkCellRenderer
* cell
, cairo_t
* cr
, GtkWidget
* /*widget*/,
251 const GdkRectangle
* /*background_area*/,
252 const GdkRectangle
* cell_area
, GtkCellRendererState flags
)
254 GValue value
= G_VALUE_INIT
;
255 g_value_init(&value
, G_TYPE_STRING
);
256 g_object_get_property(G_OBJECT(cell
), "id", &value
);
258 const char* pStr
= g_value_get_string(&value
);
259 OUString
sId(pStr
, pStr
? strlen(pStr
) : 0, RTL_TEXTENCODING_UTF8
);
261 value
= G_VALUE_INIT
;
262 g_value_init(&value
, G_TYPE_POINTER
);
263 g_object_get_property(G_OBJECT(cell
), "instance", &value
);
265 CustomCellRenderer
* cellsurface
= CUSTOM_CELL_RENDERER(cell
);
267 gpointer pWidget
= g_value_get_pointer(&value
);
271 SolarMutexGuard aGuard
;
273 custom_cell_renderer_ensure_device(cellsurface
, pWidget
);
275 Size
aSize(cell_area
->width
, cell_area
->height
);
276 // false to not bother setting the bg on resize as we'll do that
278 cellsurface
->device
->SetOutputSizePixel(aSize
, false);
280 cairo_surface_t
* pSurface
= get_underlying_cairo_surface(*cellsurface
->device
);
282 // fill surface as transparent so it can be blended with the potentially
283 // selected background
284 cairo_t
* tempcr
= cairo_create(pSurface
);
285 cairo_set_source_rgba(tempcr
, 0, 0, 0, 0);
286 cairo_set_operator(tempcr
, CAIRO_OPERATOR_SOURCE
);
288 cairo_destroy(tempcr
);
289 cairo_surface_flush(pSurface
);
291 custom_cell_renderer_render(*cellsurface
->device
, tools::Rectangle(Point(0, 0), aSize
),
292 static_cast<bool>(flags
& GTK_CELL_RENDERER_SELECTED
), sId
,
295 cairo_surface_mark_dirty(pSurface
);
297 cairo_set_source_surface(cr
, pSurface
, cell_area
->x
, cell_area
->y
);
301 #if GTK_CHECK_VERSION(4, 0, 0)
302 static void custom_cell_renderer_snapshot(GtkCellRenderer
* cell
, GtkSnapshot
* snapshot
,
303 GtkWidget
* widget
, const GdkRectangle
* background_area
,
304 const GdkRectangle
* cell_area
, GtkCellRendererState flags
)
306 graphene_rect_t rect
= GRAPHENE_RECT_INIT(
307 static_cast<float>(cell_area
->x
), static_cast<float>(cell_area
->y
),
308 static_cast<float>(cell_area
->width
), static_cast<float>(cell_area
->height
));
309 cairo_t
* cr
= gtk_snapshot_append_cairo(GTK_SNAPSHOT(snapshot
), &rect
);
310 custom_cell_renderer_render(cell
, cr
, widget
, background_area
, cell_area
, flags
);
316 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */