| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549 |
- /*
- * m2gtkshim.c - small C support library for the m2-GTK4 Modula-2 bindings.
- *
- * GNU Modula-2 cannot register GObject subclasses (no class_init /
- * vfunc overrides), which blocks widgets and paintables that need a
- * custom snapshot. This shim provides two such types whose snapshot
- * vfuncs hand a Cairo context to a Modula-2 callback, so the drawing
- * itself reuses the existing Cairo binding:
- *
- * M2GtkWidget - a GtkWidget subclass; the M2 callback is
- * void draw(GtkWidget *w, cairo_t *cr,
- * int width, int height, gpointer user);
- * M2Paintable - a GdkPaintable implementation; the M2 callback is
- * void draw(cairo_t *cr, int width, int height,
- * gpointer user);
- *
- * The M2 callback addresses and user data are supplied at construction;
- * an optional destroy notify frees the user data.
- */
- #include <gtk/gtk.h>
- /* ------------------------------------------------------------------ */
- /* M2GtkWidget */
- /* ------------------------------------------------------------------ */
- typedef void (*M2WidgetDrawFunc) (GtkWidget *widget, cairo_t *cr,
- int width, int height, gpointer user_data);
- typedef struct _M2GtkWidget M2GtkWidget;
- typedef struct _M2GtkWidgetClass M2GtkWidgetClass;
- struct _M2GtkWidget
- {
- GtkWidget parent_instance;
- M2WidgetDrawFunc draw;
- gpointer user_data;
- GDestroyNotify destroy;
- };
- struct _M2GtkWidgetClass
- {
- GtkWidgetClass parent_class;
- };
- G_DEFINE_TYPE (M2GtkWidget, m2_gtk_widget, GTK_TYPE_WIDGET)
- static void
- m2_gtk_widget_snapshot (GtkWidget *widget, GtkSnapshot *snapshot)
- {
- M2GtkWidget *self = (M2GtkWidget *) widget;
- int width = gtk_widget_get_width (widget);
- int height = gtk_widget_get_height (widget);
- if (self->draw == NULL || width <= 0 || height <= 0)
- return;
- graphene_rect_t bounds = GRAPHENE_RECT_INIT (0.f, 0.f, width, height);
- cairo_t *cr = gtk_snapshot_append_cairo (snapshot, &bounds);
- self->draw (widget, cr, width, height, self->user_data);
- cairo_destroy (cr);
- }
- static void
- m2_gtk_widget_finalize (GObject *object)
- {
- M2GtkWidget *self = (M2GtkWidget *) object;
- if (self->destroy != NULL)
- self->destroy (self->user_data);
- G_OBJECT_CLASS (m2_gtk_widget_parent_class)->finalize (object);
- }
- static void
- m2_gtk_widget_class_init (M2GtkWidgetClass *klass)
- {
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
- object_class->finalize = m2_gtk_widget_finalize;
- widget_class->snapshot = m2_gtk_widget_snapshot;
- }
- static void
- m2_gtk_widget_init (M2GtkWidget *self)
- {
- self->draw = NULL;
- self->user_data = NULL;
- self->destroy = NULL;
- }
- GtkWidget *
- m2_gtk_widget_new (M2WidgetDrawFunc draw, gpointer user_data,
- GDestroyNotify destroy)
- {
- M2GtkWidget *self = g_object_new (m2_gtk_widget_get_type (), NULL);
- self->draw = draw;
- self->user_data = user_data;
- self->destroy = destroy;
- return GTK_WIDGET (self);
- }
- /* ------------------------------------------------------------------ */
- /* M2Paintable (implements GdkPaintable) */
- /* ------------------------------------------------------------------ */
- typedef void (*M2PaintableDrawFunc) (cairo_t *cr, int width, int height,
- gpointer user_data);
- typedef struct _M2Paintable M2Paintable;
- typedef struct _M2PaintableClass M2PaintableClass;
- struct _M2Paintable
- {
- GObject parent_instance;
- M2PaintableDrawFunc draw;
- gpointer user_data;
- GDestroyNotify destroy;
- int width;
- int height;
- };
- struct _M2PaintableClass
- {
- GObjectClass parent_class;
- };
- static void
- m2_paintable_snapshot (GdkPaintable *paintable, GtkSnapshot *snapshot,
- double width, double height)
- {
- M2Paintable *self = (M2Paintable *) paintable;
- graphene_rect_t bounds = GRAPHENE_RECT_INIT (0.f, 0.f, (float) width,
- (float) height);
- cairo_t *cr = gtk_snapshot_append_cairo (snapshot, &bounds);
- if (self->draw != NULL)
- self->draw (cr, (int) width, (int) height, self->user_data);
- cairo_destroy (cr);
- }
- static int
- m2_paintable_get_intrinsic_width (GdkPaintable *paintable)
- {
- return ((M2Paintable *) paintable)->width;
- }
- static int
- m2_paintable_get_intrinsic_height (GdkPaintable *paintable)
- {
- return ((M2Paintable *) paintable)->height;
- }
- static double
- m2_paintable_get_intrinsic_aspect_ratio (GdkPaintable *paintable)
- {
- M2Paintable *self = (M2Paintable *) paintable;
- return self->height > 0 ? (double) self->width / (double) self->height : 0.0;
- }
- static void
- m2_paintable_paintable_init (GdkPaintableInterface *iface)
- {
- iface->snapshot = m2_paintable_snapshot;
- iface->get_intrinsic_width = m2_paintable_get_intrinsic_width;
- iface->get_intrinsic_height = m2_paintable_get_intrinsic_height;
- iface->get_intrinsic_aspect_ratio = m2_paintable_get_intrinsic_aspect_ratio;
- }
- G_DEFINE_TYPE_WITH_CODE (M2Paintable, m2_paintable, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
- m2_paintable_paintable_init))
- static void
- m2_paintable_finalize (GObject *object)
- {
- M2Paintable *self = (M2Paintable *) object;
- if (self->destroy != NULL)
- self->destroy (self->user_data);
- G_OBJECT_CLASS (m2_paintable_parent_class)->finalize (object);
- }
- static void
- m2_paintable_class_init (M2PaintableClass *klass)
- {
- G_OBJECT_CLASS (klass)->finalize = m2_paintable_finalize;
- }
- static void
- m2_paintable_init (M2Paintable *self)
- {
- self->draw = NULL;
- self->user_data = NULL;
- self->destroy = NULL;
- self->width = 0;
- self->height = 0;
- }
- GdkPaintable *
- m2_paintable_new (M2PaintableDrawFunc draw, int width, int height,
- gpointer user_data, GDestroyNotify destroy)
- {
- M2Paintable *self = g_object_new (m2_paintable_get_type (), NULL);
- self->draw = draw;
- self->width = width;
- self->height = height;
- self->user_data = user_data;
- self->destroy = destroy;
- return GDK_PAINTABLE (self);
- }
- /* ------------------------------------------------------------------ */
- /* M2ListModel (implements GListModel) */
- /* ------------------------------------------------------------------ */
- typedef guint (*M2ListModelGetNItemsFunc) (gpointer user_data);
- typedef gpointer (*M2ListModelGetItemFunc) (guint position,
- gpointer user_data);
- typedef struct _M2ListModel M2ListModel;
- typedef struct _M2ListModelClass M2ListModelClass;
- struct _M2ListModel
- {
- GObject parent_instance;
- M2ListModelGetNItemsFunc get_n_items;
- M2ListModelGetItemFunc get_item;
- gpointer user_data;
- GDestroyNotify destroy;
- GType item_type;
- };
- struct _M2ListModelClass
- {
- GObjectClass parent_class;
- };
- static guint
- m2_list_model_get_n_items (GListModel *list)
- {
- M2ListModel *self = (M2ListModel *) list;
- return self->get_n_items != NULL ? self->get_n_items (self->user_data) : 0;
- }
- static GType
- m2_list_model_get_item_type (GListModel *list)
- {
- return ((M2ListModel *) list)->item_type;
- }
- static gpointer
- m2_list_model_get_item (GListModel *list, guint position)
- {
- M2ListModel *self = (M2ListModel *) list;
- return self->get_item != NULL ? self->get_item (position, self->user_data)
- : NULL;
- }
- static void
- m2_list_model_list_init (GListModelInterface *iface)
- {
- iface->get_n_items = m2_list_model_get_n_items;
- iface->get_item_type = m2_list_model_get_item_type;
- iface->get_item = m2_list_model_get_item;
- }
- G_DEFINE_TYPE_WITH_CODE (M2ListModel, m2_list_model, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL,
- m2_list_model_list_init))
- static void
- m2_list_model_finalize (GObject *object)
- {
- M2ListModel *self = (M2ListModel *) object;
- if (self->destroy != NULL)
- self->destroy (self->user_data);
- G_OBJECT_CLASS (m2_list_model_parent_class)->finalize (object);
- }
- static void
- m2_list_model_class_init (M2ListModelClass *klass)
- {
- G_OBJECT_CLASS (klass)->finalize = m2_list_model_finalize;
- }
- static void
- m2_list_model_init (M2ListModel *self)
- {
- self->get_n_items = NULL;
- self->get_item = NULL;
- self->user_data = NULL;
- self->destroy = NULL;
- self->item_type = G_TYPE_OBJECT;
- }
- GListModel *
- m2_list_model_new (M2ListModelGetNItemsFunc get_n_items,
- M2ListModelGetItemFunc get_item, GType item_type,
- gpointer user_data, GDestroyNotify destroy)
- {
- M2ListModel *self = g_object_new (m2_list_model_get_type (), NULL);
- self->get_n_items = get_n_items;
- self->get_item = get_item;
- self->item_type = item_type;
- self->user_data = user_data;
- self->destroy = destroy;
- return G_LIST_MODEL (self);
- }
- void
- m2_list_model_items_changed (GListModel *model, guint position,
- guint removed, guint added)
- {
- g_list_model_items_changed (model, position, removed, added);
- }
- /* ------------------------------------------------------------------ */
- /* M2LayoutManager (subclass of GtkLayoutManager) */
- /* ------------------------------------------------------------------ */
- typedef void (*M2LayoutMeasureFunc) (GtkWidget *widget, int orientation,
- int for_size, int *minimum, int *natural,
- gpointer user_data);
- typedef void (*M2LayoutAllocateFunc) (GtkWidget *widget, int width, int height,
- int baseline, gpointer user_data);
- typedef struct _M2LayoutManager M2LayoutManager;
- typedef struct _M2LayoutManagerClass M2LayoutManagerClass;
- struct _M2LayoutManager
- {
- GtkLayoutManager parent_instance;
- M2LayoutMeasureFunc measure;
- M2LayoutAllocateFunc allocate;
- gpointer user_data;
- GDestroyNotify destroy;
- };
- struct _M2LayoutManagerClass
- {
- GtkLayoutManagerClass parent_class;
- };
- static void
- m2_layout_manager_measure (GtkLayoutManager *manager, GtkWidget *widget,
- GtkOrientation orientation, int for_size,
- int *minimum, int *natural, int *minimum_baseline,
- int *natural_baseline)
- {
- M2LayoutManager *self = (M2LayoutManager *) manager;
- *minimum = 0;
- *natural = 0;
- if (self->measure != NULL)
- self->measure (widget, (int) orientation, for_size, minimum, natural,
- self->user_data);
- *minimum_baseline = -1;
- *natural_baseline = -1;
- }
- static void
- m2_layout_manager_allocate (GtkLayoutManager *manager, GtkWidget *widget,
- int width, int height, int baseline)
- {
- M2LayoutManager *self = (M2LayoutManager *) manager;
- if (self->allocate != NULL)
- self->allocate (widget, width, height, baseline, self->user_data);
- }
- G_DEFINE_TYPE (M2LayoutManager, m2_layout_manager, GTK_TYPE_LAYOUT_MANAGER)
- static void
- m2_layout_manager_finalize (GObject *object)
- {
- M2LayoutManager *self = (M2LayoutManager *) object;
- if (self->destroy != NULL)
- self->destroy (self->user_data);
- G_OBJECT_CLASS (m2_layout_manager_parent_class)->finalize (object);
- }
- static void
- m2_layout_manager_class_init (M2LayoutManagerClass *klass)
- {
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GtkLayoutManagerClass *manager_class = GTK_LAYOUT_MANAGER_CLASS (klass);
- object_class->finalize = m2_layout_manager_finalize;
- manager_class->measure = m2_layout_manager_measure;
- manager_class->allocate = m2_layout_manager_allocate;
- }
- static void
- m2_layout_manager_init (M2LayoutManager *self)
- {
- self->measure = NULL;
- self->allocate = NULL;
- self->user_data = NULL;
- self->destroy = NULL;
- }
- GtkLayoutManager *
- m2_layout_manager_new (M2LayoutMeasureFunc measure, M2LayoutAllocateFunc allocate,
- gpointer user_data, GDestroyNotify destroy)
- {
- M2LayoutManager *self = g_object_new (m2_layout_manager_get_type (), NULL);
- self->measure = measure;
- self->allocate = allocate;
- self->user_data = user_data;
- self->destroy = destroy;
- return GTK_LAYOUT_MANAGER (self);
- }
- /* Position a child at (x, y) with the given size (helper for allocate). */
- void
- m2_layout_allocate_child (GtkWidget *child, int x, int y, int width, int height)
- {
- graphene_point_t point = GRAPHENE_POINT_INIT (x, y);
- GskTransform *transform = gsk_transform_translate (NULL, &point);
- gtk_widget_allocate (child, width, height, -1, transform);
- gsk_transform_unref (transform);
- }
- /* ------------------------------------------------------------------ */
- /* M2SnapshotPaintable (GdkPaintable using GtkSnapshot) */
- /* ------------------------------------------------------------------ */
- typedef void (*M2SnapshotDrawFunc) (GtkSnapshot *snapshot, int width,
- int height, gpointer user_data);
- typedef struct _M2SnapshotPaintable M2SnapshotPaintable;
- typedef struct _M2SnapshotPaintableClass M2SnapshotPaintableClass;
- struct _M2SnapshotPaintable
- {
- GObject parent_instance;
- M2SnapshotDrawFunc draw;
- gpointer user_data;
- GDestroyNotify destroy;
- int width;
- int height;
- };
- struct _M2SnapshotPaintableClass
- {
- GObjectClass parent_class;
- };
- static void
- m2_snapshot_paintable_snapshot (GdkPaintable *paintable, GtkSnapshot *snapshot,
- double width, double height)
- {
- M2SnapshotPaintable *self = (M2SnapshotPaintable *) paintable;
- if (self->draw != NULL)
- self->draw (snapshot, (int) width, (int) height, self->user_data);
- }
- static int
- m2_snapshot_paintable_get_intrinsic_width (GdkPaintable *paintable)
- {
- return ((M2SnapshotPaintable *) paintable)->width;
- }
- static int
- m2_snapshot_paintable_get_intrinsic_height (GdkPaintable *paintable)
- {
- return ((M2SnapshotPaintable *) paintable)->height;
- }
- static double
- m2_snapshot_paintable_get_intrinsic_aspect_ratio (GdkPaintable *paintable)
- {
- M2SnapshotPaintable *self = (M2SnapshotPaintable *) paintable;
- return self->height > 0 ? (double) self->width / (double) self->height : 0.0;
- }
- static void
- m2_snapshot_paintable_paintable_init (GdkPaintableInterface *iface)
- {
- iface->snapshot = m2_snapshot_paintable_snapshot;
- iface->get_intrinsic_width = m2_snapshot_paintable_get_intrinsic_width;
- iface->get_intrinsic_height = m2_snapshot_paintable_get_intrinsic_height;
- iface->get_intrinsic_aspect_ratio = m2_snapshot_paintable_get_intrinsic_aspect_ratio;
- }
- G_DEFINE_TYPE_WITH_CODE (M2SnapshotPaintable, m2_snapshot_paintable,
- G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
- m2_snapshot_paintable_paintable_init))
- static void
- m2_snapshot_paintable_finalize (GObject *object)
- {
- M2SnapshotPaintable *self = (M2SnapshotPaintable *) object;
- if (self->destroy != NULL)
- self->destroy (self->user_data);
- G_OBJECT_CLASS (m2_snapshot_paintable_parent_class)->finalize (object);
- }
- static void
- m2_snapshot_paintable_class_init (M2SnapshotPaintableClass *klass)
- {
- G_OBJECT_CLASS (klass)->finalize = m2_snapshot_paintable_finalize;
- }
- static void
- m2_snapshot_paintable_init (M2SnapshotPaintable *self)
- {
- self->draw = NULL;
- self->user_data = NULL;
- self->destroy = NULL;
- self->width = 0;
- self->height = 0;
- }
- GdkPaintable *
- m2_snapshot_paintable_new (M2SnapshotDrawFunc draw, int width, int height,
- gpointer user_data, GDestroyNotify destroy)
- {
- M2SnapshotPaintable *self = g_object_new (m2_snapshot_paintable_get_type (),
- NULL);
- self->draw = draw;
- self->width = width;
- self->height = height;
- self->user_data = user_data;
- self->destroy = destroy;
- return GDK_PAINTABLE (self);
- }
|