[gtkmm] Add Gtk::WidgetCustomDraw and WidgetCustomSnapshot
- From: Kjell Ahlstedt <kjellahl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtkmm] Add Gtk::WidgetCustomDraw and WidgetCustomSnapshot
- Date: Wed, 15 Feb 2017 10:00:37 +0000 (UTC)
commit 37c4076a9b71f42dfcb071cc8a90dbf7feea5b0e
Author: Kjell Ahlstedt <kjell ahlstedt bredband net>
Date: Wed Feb 15 10:58:03 2017 +0100
Add Gtk::WidgetCustomDraw and WidgetCustomSnapshot
The WidgetCustomDraw and WidgetCustomSnapshot classes make it possible
to use signal_draw() and snapshot_vfunc() in gtkmm without modification
of gtk+. Bug 775348. See also gtk+ bug 774778.
gtk/gtkmm/filelist.am | 6 +-
gtk/gtkmm/widgetcustomdraw.cc | 153 +++++++++++++++++++++++++++++++++++++
gtk/gtkmm/widgetcustomdraw.h | 118 ++++++++++++++++++++++++++++
gtk/gtkmm/widgetcustomsnapshot.cc | 92 ++++++++++++++++++++++
gtk/gtkmm/widgetcustomsnapshot.h | 89 +++++++++++++++++++++
5 files changed, 457 insertions(+), 1 deletions(-)
---
diff --git a/gtk/gtkmm/filelist.am b/gtk/gtkmm/filelist.am
index 04a80ae..3d3834d 100644
--- a/gtk/gtkmm/filelist.am
+++ b/gtk/gtkmm/filelist.am
@@ -17,7 +17,9 @@ gtkmm_files_extra_any_cc = \
styleproperty.cc \
targetentry.cc \
treemodelcolumn.cc \
- treeview_private.cc
+ treeview_private.cc \
+ widgetcustomdraw.cc \
+ widgetcustomsnapshot.cc
gtkmm_files_extra_deprecated_cc =
@@ -37,6 +39,8 @@ gtkmm_files_extra_any_h = \
targetentry.h \
treemodelcolumn.h \
treeview_private.h \
+ widgetcustomdraw.h \
+ widgetcustomsnapshot.h \
wrap_init.h
gtkmm_files_extra_deprecated_h =
diff --git a/gtk/gtkmm/widgetcustomdraw.cc b/gtk/gtkmm/widgetcustomdraw.cc
new file mode 100644
index 0000000..3d71e7b
--- /dev/null
+++ b/gtk/gtkmm/widgetcustomdraw.cc
@@ -0,0 +1,153 @@
+/* Copyright (C) 2017 The gtkmm Development Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gtkmm/widgetcustomdraw.h>
+#include <glibmm/exceptionhandler.h>
+#include <gtk/gtk.h>
+
+namespace
+{
+using CppObjectType = Gtk::WidgetCustomDraw;
+using BaseObjectType = GtkWidget;
+using BaseClassType = GtkWidgetClass;
+
+static gboolean WidgetCustomDraw_signal_draw_callback(GtkWidget* self, cairo_t* cr,void* data)
+{
+ using SlotType = sigc::slot<bool(const ::Cairo::RefPtr< ::Cairo::Context>&)>;
+
+ auto obj = dynamic_cast<CppObjectType*>(Glib::ObjectBase::_get_current_wrapper((GObject*)self));
+ // Do not try to call a signal on a disassociated wrapper.
+ if (obj)
+ {
+ try
+ {
+ if (const auto slot = Glib::SignalProxyNormal::data_to_slot(data))
+ return static_cast<int>((*static_cast<SlotType*>(slot))(
+ ::Cairo::RefPtr< ::Cairo::Context>(new ::Cairo::Context(cr, false /* has_reference */))));
+ }
+ catch (...)
+ {
+ Glib::exception_handlers_invoke();
+ }
+ }
+ return false;
+}
+
+static gboolean WidgetCustomDraw_signal_draw_notify_callback(GtkWidget* self, cairo_t* cr, void* data)
+{
+ using SlotType = sigc::slot<void(const ::Cairo::RefPtr< ::Cairo::Context>&)>;
+
+ auto obj = dynamic_cast<CppObjectType*>(Glib::ObjectBase::_get_current_wrapper((GObject*)self));
+ // Do not try to call a signal on a disassociated wrapper.
+ if (obj)
+ {
+ try
+ {
+ if (const auto slot = Glib::SignalProxyNormal::data_to_slot(data))
+ (*static_cast<SlotType*>(slot))(
+ ::Cairo::RefPtr< ::Cairo::Context>(new ::Cairo::Context(cr, false /* has_reference */)));
+ }
+ catch(...)
+ {
+ Glib::exception_handlers_invoke();
+ }
+ }
+ return false;
+}
+
+static const Glib::SignalProxyInfo WidgetCustomDraw_signal_draw_info =
+{
+ "draw",
+ (GCallback) &WidgetCustomDraw_signal_draw_callback,
+ (GCallback) &WidgetCustomDraw_signal_draw_notify_callback
+};
+
+} // anonymous namespace
+
+namespace Gtk
+{
+WidgetCustomDraw::WidgetCustomDraw()
+:
+Glib::ExtraClassInit(class_init_function)
+{
+}
+
+Glib::SignalProxy<bool(const ::Cairo::RefPtr< ::Cairo::Context>&)> WidgetCustomDraw::signal_draw()
+{
+ return Glib::SignalProxy<bool(const ::Cairo::RefPtr< ::Cairo::Context>&) >(this,
&WidgetCustomDraw_signal_draw_info);
+}
+
+bool WidgetCustomDraw::on_draw(const ::Cairo::RefPtr< ::Cairo::Context>& cr)
+{
+ const auto base = static_cast<BaseClassType*>(
+ g_type_class_peek_parent(G_OBJECT_GET_CLASS(gobject_))); // Get the parent class of the object class
(The original underlying C class).
+
+ if (base && base->draw)
+ return (*base->draw)((BaseObjectType*)gobject_, cr->cobj());
+
+ return false;
+}
+
+// static
+gboolean WidgetCustomDraw::draw_callback(GtkWidget* self, cairo_t* cr)
+{
+ const auto obj_base = static_cast<Glib::ObjectBase*>(
+ Glib::ObjectBase::_get_current_wrapper((GObject*)self));
+
+ // Non-gtkmmproc-generated custom classes implicitly call the default
+ // Glib::ObjectBase constructor, which sets is_derived_. But gtkmmproc-
+ // generated classes can use this optimisation, which avoids the unnecessary
+ // parameter conversions if there is no possibility of the virtual function
+ // being overridden:
+ if (obj_base && obj_base->is_derived_())
+ {
+ const auto obj = dynamic_cast<CppObjectType* const>(obj_base);
+ if (obj) // This can be nullptr during destruction.
+ {
+ try // Trap C++ exceptions which would normally be lost because this is a C callback.
+ {
+ // Call the virtual member method, which derived classes might override.
+ return static_cast<int>(obj->on_draw(
+ ::Cairo::RefPtr< ::Cairo::Context>(new ::Cairo::Context(cr, false /* has_reference */))));
+ }
+ catch (...)
+ {
+ Glib::exception_handlers_invoke();
+ }
+ }
+ }
+
+ const auto base = static_cast<BaseClassType*>(
+ g_type_class_peek_parent(G_OBJECT_GET_CLASS(self))); // Get the parent class of the object class (The
original underlying C class).
+
+ // Call the original underlying C function:
+ if (base && base->draw)
+ return (*base->draw)(self, cr);
+
+ return false;
+}
+
+// Addition to Gtk::Widget's class init function
+// static
+void WidgetCustomDraw::class_init_function(void* g_class, void* /* class_data */)
+{
+ g_return_if_fail(GTK_IS_WIDGET_CLASS(g_class));
+
+ const auto klass = static_cast<BaseClassType*>(g_class);
+ klass->draw = &draw_callback;
+}
+
+} // namespace Gtk
diff --git a/gtk/gtkmm/widgetcustomdraw.h b/gtk/gtkmm/widgetcustomdraw.h
new file mode 100644
index 0000000..d559b3c
--- /dev/null
+++ b/gtk/gtkmm/widgetcustomdraw.h
@@ -0,0 +1,118 @@
+/* Copyright (C) 2017 The gtkmm Development Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _GTKMM_WIDGETCUSTOMDRAW_H
+#define _GTKMM_WIDGETCUSTOMDRAW_H
+
+#include <glibmm/extraclassinit.h>
+#include <glibmm/signalproxy.h>
+#include <cairomm/context.h>
+
+using GtkWidget = struct _GtkWidget;
+
+namespace Gtk
+{
+
+/** %Widget with signal_draw().
+ *
+ * Because of the way gtk+4 renders widgets, Gtk::Widget can't wrap the draw signal.
+ * If you make a custom widget that uses the draw signal, you must derive your
+ * custom widget from both %WidgetCustomDraw and the relevant widget class.
+ * E.g. if you make a custom widget that you want to derive from Gtk::Widget,
+ * and you want to connect to signal_draw() or override the on_draw() default
+ * signal handler:
+ * @code
+ * #include <gtkmm/widgetcustomdraw.h>
+ *
+ * class MyWidget : public Gtk::WidgetCustomDraw, public Gtk::Widget
+ * {
+ * public:
+ * MyWidget()
+ * :
+ * // The GType name will be gtkmm__CustomObject_MyMidget
+ * Glib::ObjectBase("MyWidget"), // Unique class name
+ * Gtk::WidgetCustomDraw(),
+ * Gtk::Widget()
+ * {
+ * // ...
+ * }
+ * // ...
+ * protected:
+ * bool on_draw(const Cairo::RefPtr<Cairo::Context>& cr) override;
+ * // ...
+ * };
+ * @endcode
+ *
+ * %WidgetCustomDraw must be listed @e before the widget class (Gtk::Widget in
+ * the example) in the list of base classes.
+ *
+ * Do not use %WidgetCustomDraw for drawing in a Gtk::DrawingArea.
+ * %Gtk::DrawingArea uses a draw function instead of %signal_draw().
+ * See Gtk::DrawingArea::set_draw_func().
+ *
+ * Don't derive from both %WidgetCustomDraw and WidgetCustomSnapshot in the
+ * same class. It will compile, but probably at most one of signal_draw() and
+ * snapshot_vfunc() will work.
+ *
+ * @newin{3,90}
+ * @ingroup Widgets
+ */
+class WidgetCustomDraw : public Glib::ExtraClassInit
+{
+public:
+ WidgetCustomDraw();
+
+ /**
+ * @par Slot Prototype:
+ * <tt>bool on_my_%draw(const ::Cairo::RefPtr< ::Cairo::Context>& cr)</tt>
+ *
+ * This signal is emitted when a widget is supposed to render itself.
+ * The widget's top left corner must be painted at the origin of
+ * the passed in context and be sized to the values returned by
+ * Gtk::Widget::get_allocated_width() and
+ * Gtk::Widget::get_allocated_height().
+ *
+ * Signal handlers connected to this signal can modify the cairo
+ * context passed as @a cr in any way they like and don't need to
+ * restore it. The signal emission takes care of calling cairo_save()
+ * before and cairo_restore() after invoking the handler.
+ *
+ * The signal handler will get a @a cr with a clip region already set to the
+ * widget's dirty region, i.e. to the area that needs repainting. Complicated
+ * widgets that want to avoid redrawing themselves completely can get the full
+ * extents of the clip region with Cairo::Context::get_clip_extents(), or they can
+ * get a finer-grained representation of the dirty region with
+ * Cairo::Context::copy_clip_rectangle_list().
+ *
+ * @param cr The cairo context to draw to.
+ * @return <tt>true</tt> to stop other handlers from being invoked for the event.
+ * <tt>false</tt> to propagate the event further.
+ */
+ Glib::SignalProxy<bool(const ::Cairo::RefPtr< ::Cairo::Context>&)> signal_draw();
+
+protected:
+ /// This is a default handler for signal_draw().
+ virtual bool on_draw(const ::Cairo::RefPtr< ::Cairo::Context>& cr);
+
+private:
+ static gboolean draw_callback(GtkWidget* self, cairo_t* cr);
+ static void class_init_function(void* g_class, void* class_data);
+
+}; // end WidgetCustomDraw
+
+} // namespace Gtk
+
+#endif // _GTKMM_WIDGETCUSTOMDRAW_H
diff --git a/gtk/gtkmm/widgetcustomsnapshot.cc b/gtk/gtkmm/widgetcustomsnapshot.cc
new file mode 100644
index 0000000..1813c56
--- /dev/null
+++ b/gtk/gtkmm/widgetcustomsnapshot.cc
@@ -0,0 +1,92 @@
+/* Copyright (C) 2017 The gtkmm Development Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gtkmm/widgetcustomsnapshot.h>
+#include <glibmm/exceptionhandler.h>
+#include <gtk/gtk.h>
+
+using CppObjectType = Gtk::WidgetCustomSnapshot;
+using BaseObjectType = GtkWidget;
+using BaseClassType = GtkWidgetClass;
+
+namespace Gtk
+{
+WidgetCustomSnapshot::WidgetCustomSnapshot()
+:
+Glib::ExtraClassInit(class_init_function)
+{
+}
+
+void WidgetCustomSnapshot::snapshot_vfunc(Snapshot& snapshot)
+{
+ const auto base = static_cast<BaseClassType*>(
+ g_type_class_peek_parent(G_OBJECT_GET_CLASS(gobject_)) // Get the parent class of the object class
(The original underlying C class).
+ );
+
+ if (base && base->snapshot)
+ (*base->snapshot)((BaseObjectType*)gobject_, snapshot.gobj());
+}
+
+// static
+void WidgetCustomSnapshot::snapshot_vfunc_callback(GtkWidget* self, GtkSnapshot* snapshot)
+{
+ const auto obj_base = static_cast<Glib::ObjectBase*>(
+ Glib::ObjectBase::_get_current_wrapper((GObject*)self));
+
+ // Non-gtkmmproc-generated custom classes implicitly call the default
+ // Glib::ObjectBase constructor, which sets is_derived_. But gtkmmproc-
+ // generated classes can use this optimisation, which avoids the unnecessary
+ // parameter conversions if there is no possibility of the virtual function
+ // being overridden:
+ if (obj_base && obj_base->is_derived_())
+ {
+ const auto obj = dynamic_cast<CppObjectType* const>(obj_base);
+ if (obj) // This can be nullptr during destruction.
+ {
+ try // Trap C++ exceptions which would normally be lost because this is a C callback.
+ {
+ // Call the virtual member method, which derived classes must override.
+ obj->snapshot_vfunc(*Glib::wrap(snapshot));
+ return;
+ }
+ catch (...)
+ {
+ Glib::exception_handlers_invoke();
+ }
+ }
+ }
+
+ BaseClassType *const base = static_cast<BaseClassType*>(
+ g_type_class_peek_parent(G_OBJECT_GET_CLASS(self)) // Get the parent class of the object class (The
original underlying C class).
+ );
+
+ // Call the original underlying C function:
+ if (base && base->snapshot)
+ (*base->snapshot)(self, snapshot);
+}
+
+// Addition to Gtk::Widget's class init function
+// static
+void WidgetCustomSnapshot::class_init_function(void* g_class, void* /* class_data */)
+{
+ g_return_if_fail(GTK_IS_WIDGET_CLASS(g_class));
+
+ const auto klass = static_cast<BaseClassType*>(g_class);
+ klass->snapshot = &snapshot_vfunc_callback;
+}
+
+
+} // namespace Gtk
diff --git a/gtk/gtkmm/widgetcustomsnapshot.h b/gtk/gtkmm/widgetcustomsnapshot.h
new file mode 100644
index 0000000..d115c5e
--- /dev/null
+++ b/gtk/gtkmm/widgetcustomsnapshot.h
@@ -0,0 +1,89 @@
+/* Copyright (C) 2017 The gtkmm Development Team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _GTKMM_WIDGETCUSTOMSNAPSHOT_H
+#define _GTKMM_WIDGETCUSTOMSNAPSHOT_H
+
+#include <glibmm/extraclassinit.h>
+#include <gtkmm/snapshot.h>
+
+using GtkWidget = struct _GtkWidget;
+using GtkSnapshot = struct _GtkSnapshot;
+
+namespace Gtk
+{
+
+/** %Widget with snapshot_vfunc().
+ *
+ * Because of the way gtk+4 renders widgets, Gtk::Widget can't wrap the snapshot virtual function.
+ * If you make a custom widget that uses the snapshot vfunc, you must derive your
+ * custom widget from both %WidgetCustomSnapshot and the relevant widget class.
+ * E.g. if you make a custom widget that you want to derive from Gtk::Widget,
+ * and you want snapshot_vfunc() to be called:
+ * @code
+ * #include <gtkmm/widgetcustomsnapshot.h>
+ *
+ * class MyWidget : public Gtk::WidgetCustomSnapshot, public Gtk::Widget
+ * {
+ * public:
+ * MyWidget()
+ * :
+ * // The GType name will be gtkmm__CustomObject_MyMidget
+ * Glib::ObjectBase("MyWidget"), // Unique class name
+ * Gtk::WidgetCustomSnapshot(),
+ * Gtk::Widget()
+ * {
+ * // ...
+ * }
+ * // ...
+ * protected:
+ * void snapshot_vfunc(Gtk::Snapshot& snapshot) override;
+ * // ...
+ * };
+ * @endcode
+ *
+ * %WidgetCustomSnapshot must be listed @e before the widget class (Gtk::Widget in
+ * the example) in the list of base classes.
+ *
+ * Do not use %WidgetCustomSnapshot for drawing in a Gtk::DrawingArea.
+ * %Gtk::DrawingArea uses a draw function instead of %snapshot_vfunc().
+ * See Gtk::DrawingArea::set_draw_func().
+ *
+ * Don't derive from both WidgetCustomDraw and %WidgetCustomSnapshot in the
+ * same class. It will compile, but probably at most one of signal_draw() and
+ * snapshot_vfunc() will work.
+ *
+ * @newin{3,90}
+ * @ingroup Widgets
+ */
+class WidgetCustomSnapshot : public Glib::ExtraClassInit
+{
+public:
+ WidgetCustomSnapshot();
+
+protected:
+ /// Called when a widget is supposed to create a snapshot of itself.
+ virtual void snapshot_vfunc(Snapshot& snapshot);
+
+private:
+ static void snapshot_vfunc_callback(GtkWidget* self, GtkSnapshot* snapshot);
+ static void class_init_function(void* g_class, void* class_data);
+
+}; // end WidgetCustomSnapshot
+
+} // namespace Gtk
+
+#endif // _GTKMM_WIDGETCUSTOMSNAPSHOT_H
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]