summaryrefslogtreecommitdiff
path: root/new/parent_unix.c
diff options
context:
space:
mode:
Diffstat (limited to 'new/parent_unix.c')
-rw-r--r--new/parent_unix.c183
1 files changed, 183 insertions, 0 deletions
diff --git a/new/parent_unix.c b/new/parent_unix.c
new file mode 100644
index 0000000..f9c8db1
--- /dev/null
+++ b/new/parent_unix.c
@@ -0,0 +1,183 @@
+// 13 august 2014
+#include "uipriv_unix.h"
+
+#define uipParentType (uipParent_get_type())
+#define uipParent(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), uipParentType, uipParent))
+#define uipIsParent(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), uipParentType))
+#define uipParentClass(class) (G_TYPE_CHECK_CLASS_CAST((class), uipParentType, uipParentClass))
+#define uipIsParentClass(class) (G_TYPE_CHECK_CLASS_TYPE((class), uipParent))
+#define uipGetParentClass(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), uipParentType, uipParentClass))
+
+typedef struct uipParent uipParent;
+typedef struct uipParentClass uipParentClass;
+
+struct uipParent {
+ GtkContainer parent_instance;
+ // this is what triggers the resizing of all the children
+ uiControl *child;
+ // these are the actual children widgets of the container as far as GTK+ is concerned
+ GPtrArray *children; // for forall()
+ intmax_t marginLeft;
+ intmax_t marginTop;
+ intmax_t marginRight;
+ intmax_t marginBottom;
+};
+
+struct uipParentClass {
+ GtkContainerClass parent_class;
+};
+
+G_DEFINE_TYPE(uipParent, uipParent, GTK_TYPE_CONTAINER)
+
+static void uipParent_init(uipParent *p)
+{
+ if (options.debugLogAllocations)
+ fprintf(stderr, "%p alloc uipParent\n", p);
+ p->children = g_ptr_array_new();
+ gtk_widget_set_has_window(GTK_WIDGET(c), FALSE);
+}
+
+// instead of having GtkContainer itself unref all our controls, we'll run our own uiControlDestroy() functions for child, which will do that and more
+// we still chain up because we need to, but by that point there will be no children for GtkContainer to free
+static void uipParent_dispose(GObject *obj)
+{
+ uipParent *p = uipParent(obj);
+
+ if (p->children != NULL) {
+ g_ptr_array_unref(c->children);
+ p->children = NULL;
+ }
+ if (p->child != NULL) {
+ uiControlDestroy(c->child);
+ p->child = NULL;
+ }
+ G_OBJECT_CLASS(uipParent_parent_class)->dispose(obj);
+}
+
+static void uipParent_finalize(GObject *obj)
+{
+ G_OBJECT_CLASS(uipParent_parent_class)->finalize(obj);
+ if (options.debugLogAllocations)
+ fprintf(stderr, "%p free\n", obj);
+}
+
+static void uipParent_add(GtkContainer *container, GtkWidget *widget)
+{
+ uipParent *p = uipParent(container);
+
+ gtk_widget_set_parent(widget, GTK_WIDGET(c));
+ if (p->children != NULL)
+ g_ptr_array_add(p->children, widget);
+}
+
+static void uipParent_remove(GtkContainer *container, GtkWidget *widget)
+{
+ uipParent *p = uipParent(container);
+
+ gtk_widget_unparent(widget);
+ if (p->children != NULL)
+ g_ptr_array_remove(p->children, widget);
+}
+
+#define gtkXPadding 12
+#define gtkYPadding 6
+
+static void uipParent_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
+{
+ uipParent *p = uipParent(widget);
+ uiSizing d;
+ intmax_t x, y, width, height;
+
+ gtk_widget_set_allocation(GTK_WIDGET(c), allocation);
+ if (c->child == NULL)
+ return;
+ x = allocation->x + p->marginLeft;
+ y = allocation->y + p->marginTop;
+ width = allocation->width - (p->marginLeft + p->marginRight);
+ height = allocation->height - (p->marginTop + p->marginBottom);
+ d.xPadding = gtkXPadding;
+ d.yPadding = gtkYPadding;
+ uiControlResize(c->child, x, y, width, height, &d);
+}
+
+struct forall {
+ GtkCallback callback;
+ gpointer data;
+};
+
+static void doforall(gpointer obj, gpointer data)
+{
+ struct forall *s = (struct forall *) data;
+
+ (*(s->callback))(GTK_WIDGET(obj), s->data);
+}
+
+static void uipParent_forall(GtkContainer *container, gboolean includeInternals, GtkCallback callback, gpointer data)
+{
+ uipParent *p = uipParent(container);
+ struct forall s;
+
+ s.callback = callback;
+ s.data = data;
+ if (p->children != NULL)
+ g_ptr_array_foreach(c->children, doforall, &s);
+}
+
+static void uipParent_class_init(uipParentClass *class)
+{
+ G_OBJECT_CLASS(class)->dispose = uipParent_dispose;
+ G_OBJECT_CLASS(class)->finalize = uipParent_finalize;
+ GTK_WIDGET_CLASS(class)->size_allocate = uipParent_size_allocate;
+ GTK_CONTAINER_CLASS(class)->add = uipParent_add;
+ GTK_CONTAINER_CLASS(class)->remove = uipParent_remove;
+ GTK_CONTAINER_CLASS(class)->forall = uipParent_forall;
+}
+
+static uintptr_t parentHandle(uiParent *p)
+{
+ uipParent *pp = uipParent(p->Internal);
+
+ return (uintptr_t) pp;
+}
+
+static void parentSetChild(uiParent *p, uiControl *child)
+{
+ uipParent *pp = uipParent(p->Internal);
+
+ pp->child = child;
+ if (pp->child != NULL)
+ uiControlSetParent(child, p);
+}
+
+static void parentSetMargins(uiParent *p, intmax_t left, intmax_t top, intmax_t right, intmax_t bottom)
+{
+ uipParent *pp = uipParent(p->Internal);
+
+ pp->marginLeft = left;
+ pp->marginTop = top;
+ pp->marginRight = right;
+ pp->marginBottom = bottom;
+}
+
+static void parentUpdate(uiParent *p)
+{
+ uipParent *pp = uipParent(p->Internal);
+
+ gtk_queue_resize(GTK_WIDGET(pp));
+}
+
+uiParent *uiNewParent(uintptr_t osParent)
+{
+ uiParent *p;
+
+ p = uiNew(uiParent);
+ p->Internal = g_object_new(uipParentType, NULL);
+ p->Handle = parentHandle;
+ p->SetChild = parentSetChild;
+ p->SetMargins = parentSetMargins;
+ p->Update = parentUpdate;
+ gtk_container_add(GTK_CONTAINER(osParent), GTK_WIDGET(p->Internal));
+ // and make it visible by default
+ gtk_widget_show_all(GTK_WIDGET(p->internal));
+ return p;
+}