m2gtkshim.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. /*
  2. * m2gtkshim.c - small C support library for the m2-GTK4 Modula-2 bindings.
  3. *
  4. * GNU Modula-2 cannot register GObject subclasses (no class_init /
  5. * vfunc overrides), which blocks widgets and paintables that need a
  6. * custom snapshot. This shim provides two such types whose snapshot
  7. * vfuncs hand a Cairo context to a Modula-2 callback, so the drawing
  8. * itself reuses the existing Cairo binding:
  9. *
  10. * M2GtkWidget - a GtkWidget subclass; the M2 callback is
  11. * void draw(GtkWidget *w, cairo_t *cr,
  12. * int width, int height, gpointer user);
  13. * M2Paintable - a GdkPaintable implementation; the M2 callback is
  14. * void draw(cairo_t *cr, int width, int height,
  15. * gpointer user);
  16. *
  17. * The M2 callback addresses and user data are supplied at construction;
  18. * an optional destroy notify frees the user data.
  19. */
  20. #include <gtk/gtk.h>
  21. /* ------------------------------------------------------------------ */
  22. /* M2GtkWidget */
  23. /* ------------------------------------------------------------------ */
  24. typedef void (*M2WidgetDrawFunc) (GtkWidget *widget, cairo_t *cr,
  25. int width, int height, gpointer user_data);
  26. typedef struct _M2GtkWidget M2GtkWidget;
  27. typedef struct _M2GtkWidgetClass M2GtkWidgetClass;
  28. struct _M2GtkWidget
  29. {
  30. GtkWidget parent_instance;
  31. M2WidgetDrawFunc draw;
  32. gpointer user_data;
  33. GDestroyNotify destroy;
  34. };
  35. struct _M2GtkWidgetClass
  36. {
  37. GtkWidgetClass parent_class;
  38. };
  39. G_DEFINE_TYPE (M2GtkWidget, m2_gtk_widget, GTK_TYPE_WIDGET)
  40. static void
  41. m2_gtk_widget_snapshot (GtkWidget *widget, GtkSnapshot *snapshot)
  42. {
  43. M2GtkWidget *self = (M2GtkWidget *) widget;
  44. int width = gtk_widget_get_width (widget);
  45. int height = gtk_widget_get_height (widget);
  46. if (self->draw == NULL || width <= 0 || height <= 0)
  47. return;
  48. graphene_rect_t bounds = GRAPHENE_RECT_INIT (0.f, 0.f, width, height);
  49. cairo_t *cr = gtk_snapshot_append_cairo (snapshot, &bounds);
  50. self->draw (widget, cr, width, height, self->user_data);
  51. cairo_destroy (cr);
  52. }
  53. static void
  54. m2_gtk_widget_finalize (GObject *object)
  55. {
  56. M2GtkWidget *self = (M2GtkWidget *) object;
  57. if (self->destroy != NULL)
  58. self->destroy (self->user_data);
  59. G_OBJECT_CLASS (m2_gtk_widget_parent_class)->finalize (object);
  60. }
  61. static void
  62. m2_gtk_widget_class_init (M2GtkWidgetClass *klass)
  63. {
  64. GObjectClass *object_class = G_OBJECT_CLASS (klass);
  65. GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
  66. object_class->finalize = m2_gtk_widget_finalize;
  67. widget_class->snapshot = m2_gtk_widget_snapshot;
  68. }
  69. static void
  70. m2_gtk_widget_init (M2GtkWidget *self)
  71. {
  72. self->draw = NULL;
  73. self->user_data = NULL;
  74. self->destroy = NULL;
  75. }
  76. GtkWidget *
  77. m2_gtk_widget_new (M2WidgetDrawFunc draw, gpointer user_data,
  78. GDestroyNotify destroy)
  79. {
  80. M2GtkWidget *self = g_object_new (m2_gtk_widget_get_type (), NULL);
  81. self->draw = draw;
  82. self->user_data = user_data;
  83. self->destroy = destroy;
  84. return GTK_WIDGET (self);
  85. }
  86. /* ------------------------------------------------------------------ */
  87. /* M2Paintable (implements GdkPaintable) */
  88. /* ------------------------------------------------------------------ */
  89. typedef void (*M2PaintableDrawFunc) (cairo_t *cr, int width, int height,
  90. gpointer user_data);
  91. typedef struct _M2Paintable M2Paintable;
  92. typedef struct _M2PaintableClass M2PaintableClass;
  93. struct _M2Paintable
  94. {
  95. GObject parent_instance;
  96. M2PaintableDrawFunc draw;
  97. gpointer user_data;
  98. GDestroyNotify destroy;
  99. int width;
  100. int height;
  101. };
  102. struct _M2PaintableClass
  103. {
  104. GObjectClass parent_class;
  105. };
  106. static void
  107. m2_paintable_snapshot (GdkPaintable *paintable, GtkSnapshot *snapshot,
  108. double width, double height)
  109. {
  110. M2Paintable *self = (M2Paintable *) paintable;
  111. graphene_rect_t bounds = GRAPHENE_RECT_INIT (0.f, 0.f, (float) width,
  112. (float) height);
  113. cairo_t *cr = gtk_snapshot_append_cairo (snapshot, &bounds);
  114. if (self->draw != NULL)
  115. self->draw (cr, (int) width, (int) height, self->user_data);
  116. cairo_destroy (cr);
  117. }
  118. static int
  119. m2_paintable_get_intrinsic_width (GdkPaintable *paintable)
  120. {
  121. return ((M2Paintable *) paintable)->width;
  122. }
  123. static int
  124. m2_paintable_get_intrinsic_height (GdkPaintable *paintable)
  125. {
  126. return ((M2Paintable *) paintable)->height;
  127. }
  128. static double
  129. m2_paintable_get_intrinsic_aspect_ratio (GdkPaintable *paintable)
  130. {
  131. M2Paintable *self = (M2Paintable *) paintable;
  132. return self->height > 0 ? (double) self->width / (double) self->height : 0.0;
  133. }
  134. static void
  135. m2_paintable_paintable_init (GdkPaintableInterface *iface)
  136. {
  137. iface->snapshot = m2_paintable_snapshot;
  138. iface->get_intrinsic_width = m2_paintable_get_intrinsic_width;
  139. iface->get_intrinsic_height = m2_paintable_get_intrinsic_height;
  140. iface->get_intrinsic_aspect_ratio = m2_paintable_get_intrinsic_aspect_ratio;
  141. }
  142. G_DEFINE_TYPE_WITH_CODE (M2Paintable, m2_paintable, G_TYPE_OBJECT,
  143. G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
  144. m2_paintable_paintable_init))
  145. static void
  146. m2_paintable_finalize (GObject *object)
  147. {
  148. M2Paintable *self = (M2Paintable *) object;
  149. if (self->destroy != NULL)
  150. self->destroy (self->user_data);
  151. G_OBJECT_CLASS (m2_paintable_parent_class)->finalize (object);
  152. }
  153. static void
  154. m2_paintable_class_init (M2PaintableClass *klass)
  155. {
  156. G_OBJECT_CLASS (klass)->finalize = m2_paintable_finalize;
  157. }
  158. static void
  159. m2_paintable_init (M2Paintable *self)
  160. {
  161. self->draw = NULL;
  162. self->user_data = NULL;
  163. self->destroy = NULL;
  164. self->width = 0;
  165. self->height = 0;
  166. }
  167. GdkPaintable *
  168. m2_paintable_new (M2PaintableDrawFunc draw, int width, int height,
  169. gpointer user_data, GDestroyNotify destroy)
  170. {
  171. M2Paintable *self = g_object_new (m2_paintable_get_type (), NULL);
  172. self->draw = draw;
  173. self->width = width;
  174. self->height = height;
  175. self->user_data = user_data;
  176. self->destroy = destroy;
  177. return GDK_PAINTABLE (self);
  178. }