From 335bfe8b1ae44f27bde5a585bfbe304329f8b742 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Sat, 25 Apr 2015 18:28:49 -0400 Subject: [PATCH] Revert "Nuked uiParent/uiOSContainer, replacing it with the older uintptr_t/Update() method. I'm not sure if I'm happy with *this* design either... I really have no idea what's clean or elegant here ^^' Fixed initial title/size setting not taking effect on the GTK+ Window bckend." I have no idea what I'm doing or thinking but the other way makes things harder on Windows... This reverts commit 9e18ee03e6f683be506687a6c90e38de01a9e9fb. --- new/box.c | 46 ++++++++--------- new/ui.idl | 12 ++++- new/unix/oscontainer.c | 109 +++++++++++++++++++++++++++-------------- new/unix/uipriv_unix.h | 29 ----------- new/unix/window.c | 29 ++++------- 5 files changed, 116 insertions(+), 109 deletions(-) diff --git a/new/box.c b/new/box.c index 6ba9cdc5..a1438486 100644 --- a/new/box.c +++ b/new/box.c @@ -13,7 +13,7 @@ struct box { uintmax_t cap; int vertical; int hasParent; - uintptr_t osContainer; + uiOSContainer *osContainer; int padded; int userHid; int containerHid; @@ -37,7 +37,7 @@ static void boxDestroy(uiControl *c) complain("attempt to destroy a uiControl at %p while it still has a parent", c); for (i = 0; i < b->len; i++) { uiControlSetHasParent(b->controls[i].c, 0); - uiControlSetOSContainer(b->controls[i].c, 0); + uiControlSetOSContainer(b->controls[i].c, NULL); uiControlDestroy(b->controls[i].c); } uiFree(b->controls); @@ -56,20 +56,20 @@ static void boxSetHasParent(uiControl *c, int hasParent) b->hasParent = hasParent; } -static void boxSetOSContainer(uiControl *c, uintptr_t osContainer) +static void boxSetOSContainer(uiControl *c, uiOSContainer *osContainer) { box *b = (box *) c; uintmax_t i; - uintptr_t oldcontainer; + uiOSContainer *oldcontainer; oldcontainer = b->osContainer; b->osContainer = osContainer; for (i = 0; i < b->len; i++) uiControlSetOSContainer(b->controls[i].c, b->osContainer); - if (oldcontainer != 0) - uiUpdateOSContainer(oldcontainer); - if (b->osContainer != 0) - uiUpdateOSContainer(b->osContainer); + if (oldcontainer != NULL) + uiOSContainerUpdate(oldcontainer); + if (b->osContainer != NULL) + uiOSContainerUpdate(b->osContainer); } static void boxPreferredSize(uiControl *c, uiSizing *d, intmax_t *width, intmax_t *height) @@ -231,8 +231,8 @@ static void boxShow(uiControl *c) if (!b->containerHid) { for (i = 0; i < b->len; i++) uiControlContainerShow(b->controls[i].c); - if (b->osContainer != 0) - uiUpdateOSContainer(b->osContainer); + if (b->osContainer != NULL) + uiOSContainerUpdate(b->osContainer); } } @@ -244,8 +244,8 @@ static void boxHide(uiControl *c) b->userHid = 1; for (i = 0; i < b->len; i++) uiControlContainerHide(b->controls[i].c); - if (b->osContainer != 0) - uiUpdateOSContainer(b->osContainer); + if (b->osContainer != NULL) + uiOSContainerUpdate(b->osContainer); } static void boxContainerShow(uiControl *c) @@ -257,8 +257,8 @@ static void boxContainerShow(uiControl *c) if (!b->userHid) { for (i = 0; i < b->len; i++) uiControlContainerShow(b->controls[i].c); - if (b->osContainer != 0) - uiUpdateOSContainer(b->osContainer); + if (b->osContainer != NULL) + uiOSContainerUpdate(b->osContainer); } } @@ -270,8 +270,8 @@ static void boxContainerHide(uiControl *c) b->containerHid = 1; for (i = 0; i < b->len; i++) uiControlContainerHide(b->controls[i].c); - if (b->osContainer != 0) - uiUpdateOSContainer(b->osContainer); + if (b->osContainer != NULL) + uiOSContainerUpdate(b->osContainer); } static void boxEnable(uiControl *c) @@ -330,9 +330,9 @@ static void boxAppend(uiBox *ss, uiControl *c, int stretchy) b->controls[b->len].c = c; b->controls[b->len].stretchy = stretchy; b->len++; // must be here for OS container updates to work - if (b->osContainer != 0) { + if (b->osContainer != NULL) { uiControlSetOSContainer(b->controls[b->len - 1].c, b->osContainer); - uiUpdateOSContainer(b->osContainer); + uiOSContainerUpdate(b->osContainer); } } @@ -349,9 +349,9 @@ static void boxDelete(uiBox *ss, uintmax_t index) // TODO memset the last one to NULL b->len--; uiControlSetHasParent(removed, 0); - if (b->osContainer != 0) { - uiControlSetOSContainer(removed, 0); - uiUpdateOSContainer(b->osContainer); + if (b->osContainer != NULL) { + uiControlSetOSContainer(removed, NULL); + uiOSContainerUpdate(b->osContainer); } } @@ -367,8 +367,8 @@ static void boxSetPadded(uiBox *ss, int padded) box *b = (box *) ss; b->padded = padded; - if (b->osContainer != 0) - uiUpdateOSContainer(b->osContainer); + if (b->osContainer != NULL) + uiOSContainerUpdate(b->osContainer); } uiBox *uiNewHorizontalBox(void) diff --git a/new/ui.idl b/new/ui.idl index ce44b448..4f6d288b 100644 --- a/new/ui.idl +++ b/new/ui.idl @@ -47,7 +47,7 @@ interface Control { func Destroy(void); func Handle(void) uintptr_t; func SetHasParent(hasParent int); - func SetOSContainer(handle uintptr_t); + func SetOSContainer(c *OSContainer); func PreferredSize(d *Sizing, width *intmax_t, height *intmax_t); func Resize(x intmax_t, y intmax_t, width intmax_t, height intmax_t, d *Sizing); func Visible(void) int; @@ -61,7 +61,15 @@ interface Control { func ContainerDisable(void); }; -func UpdateOSContainer(handle uintptr_t); +interface OSContainer { + field Internal *void; + func Destroy(void); + func Handle(void) uintptr_t; + func SetMainControl(c *Control); + func SetMargins(left intmax_t, top intmax_t, right intmax_t, bottom intmax_t); + func Update(void); +}; +func NewOSContainer(osParent uintptr_t) *OSContainer; interface Window { func Destroy(void); diff --git a/new/unix/oscontainer.c b/new/unix/oscontainer.c index 68713c80..a690a63a 100644 --- a/new/unix/oscontainer.c +++ b/new/unix/oscontainer.c @@ -1,16 +1,30 @@ // 13 august 2014 #include "uipriv_unix.h" -// In GTK+, many containers (GtkWindow, GtkNotebook, GtkFrame) can only have one child. -// (In the case of GtkNotebook, each child widget is a single page.) -// GtkFrame and GtkLayout, the official "anything goes" containers, are buggy and ineffective. -// This custom container does what we need just fine. -// uiWindow, uiTab, and uiGroup will keep private instances of this special container, and it will be the OS container given to each uiControl that becomes a child of those three controls. +#define uipOSContainerType (uipOSContainer_get_type()) +#define uipOSContainer(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), uipOSContainerType, uipOSContainer)) +#define uipIsOSContainer(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), uipOSContainerType)) +#define uipOSContainerClass(class) (G_TYPE_CHECK_CLASS_CAST((class), uipOSContainerType, uipOSContainerClass)) +#define uipIsOSContainerClass(class) (G_TYPE_CHECK_CLASS_TYPE((class), uipOSContainer)) +#define uipGetParentClass(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), uipOSContainerType, uipOSContainerClass)) -// This container maintains a "main control", which is the uiControl that is resized alongside the container. -// It also keeps track of all the GtkWidgets that are in the uiControl for the purposes of GTK+ internals. -// Finally, it also handles margining. -// In other words, it does everything uiWindow, uiTab, and uiGroup need to do to keep track of controls. +typedef struct uipOSContainer uipOSContainer; +typedef struct uipOSContainerClass uipOSContainerClass; + +struct uipOSContainer { + GtkContainer parent_instance; + uiControl *mainControl; + GPtrArray *children; // for forall() + intmax_t marginLeft; + intmax_t marginTop; + intmax_t marginRight; + intmax_t marginBottom; + gboolean canDestroy; +}; + +struct uipOSContainerClass { + GtkContainerClass parent_class; +}; G_DEFINE_TYPE(uipOSContainer, uipOSContainer, GTK_TYPE_CONTAINER) @@ -28,12 +42,12 @@ static void uipOSContainer_dispose(GObject *obj) { uipOSContainer *c = uipOSContainer(obj); - // don't free mainControl here; that should have been done by osContainerDestroy() + // don't free mainControl here; that should have been done by uiOSContainerDestroy() if (!c->canDestroy) - complain("attempt to dispose uipOSContainer at %p before osContainerDestroy()", c); + complain("attempt to dispose uiOSContainer with uipOSContainer at %p before uiOSContainerDestroy()", c); if (c->children != NULL) { if (c->children->len != 0) - complain("disposing uipOSContainer at %p while there are still children", c); + complain("disposing uiOSContainer with uipOSContainer at %p while there are still children", c); g_ptr_array_unref(c->children); c->children = NULL; } @@ -45,7 +59,7 @@ static void uipOSContainer_finalize(GObject *obj) uipOSContainer *c = uipOSContainer(obj); if (!c->canDestroy) - complain("attempt to finalize uipOSContainer at %p before osContainerDestroy()", c); + complain("attempt to finalize uiOSContainer with uipOSContainer at %p before uiOSContainerDestroy()", c); G_OBJECT_CLASS(uipOSContainer_parent_class)->finalize(obj); if (options.debugLogAllocations) fprintf(stderr, "%p free\n", obj); @@ -124,59 +138,82 @@ static void uipOSContainer_class_init(uipOSContainerClass *class) GTK_CONTAINER_CLASS(class)->forall = uipOSContainer_forall; } -GtkWidget *newOSContainer(void) -{ - GtkWidget *c; +// TODO convert other methods of other backends to pp arg p instance variable - c = GTK_WIDGET(g_object_new(uipOSContainerType, NULL)); - // make it visible by default - gtk_widget_show_all(c); - // hold a reference to ourselves to keep ourselves alive when we're removed from whatever container we wind up in - g_object_ref_sink(c); - return c; -} - -void osContainerDestroy(uipOSContainer *c) +static void parentDestroy(uiOSContainer *cc) { + uipOSContainer *c = uipOSContainer(cc->Internal); + // first, destroy the main control if (c->mainControl != NULL) { // we have to do this before we can destroy controls - // TODO clean this up a bit uiControlSetHasParent(c->mainControl, 0); - uiControlSetOSContainer(c->mainControl, 0); + uiControlSetOSContainer(c->mainControl, NULL); uiControlDestroy(c->mainControl); c->mainControl = NULL; } // now we can mark the parent as ready to be destroyed c->canDestroy = TRUE; - // finally, actually go ahead and destroy ourselves - g_object_unref(c); + // finally, destroy the parent + g_object_unref(G_OBJECT(c)); + // and free ourselves + uiFree(cc); } -void osContainerSetMainControl(uipOSContainer *c, uiControl *mainControl) +static uintptr_t parentHandle(uiOSContainer *cc) { + uipOSContainer *c = uipOSContainer(cc->Internal); + + return (uintptr_t) c; +} + +static void parentSetMainControl(uiOSContainer *cc, uiControl *mainControl) +{ + uipOSContainer *c = uipOSContainer(cc->Internal); + if (c->mainControl != NULL) { uiControlSetHasParent(c->mainControl, 0); - uiControlSetOSContainer(c->mainControl, 0); + uiControlSetOSContainer(c->mainControl, NULL); } c->mainControl = mainControl; if (c->mainControl != NULL) { uiControlSetHasParent(c->mainControl, 1); - uiControlSetOSContainer(c->mainControl, (uintptr_t) c); + uiControlSetOSContainer(c->mainControl, cc); } - uiUpdateOSContainer((uintptr_t) c); } -void osContainerSetMargins(uipOSContainer *c, intmax_t left, intmax_t top, intmax_t right, intmax_t bottom) +static void parentSetMargins(uiOSContainer *cc, intmax_t left, intmax_t top, intmax_t right, intmax_t bottom) { + uipOSContainer *c = uipOSContainer(cc->Internal); + c->marginLeft = left; c->marginTop = top; c->marginRight = right; c->marginBottom = bottom; - uiUpdateOSContainer((uintptr_t) c); } -void uiUpdateOSContainer(uintptr_t c) +static void parentUpdate(uiOSContainer *cc) { + uipOSContainer *c = uipOSContainer(cc->Internal); + gtk_widget_queue_resize(GTK_WIDGET(c)); } + +uiOSContainer *uiNewOSContainer(uintptr_t osParent) +{ + uiOSContainer *c; + + c = uiNew(uiOSContainer); + c->Internal = g_object_new(uipOSContainerType, NULL); + c->Destroy = parentDestroy; + c->Handle = parentHandle; + c->SetMainControl = parentSetMainControl; + c->SetMargins = parentSetMargins; + c->Update = parentUpdate; + gtk_container_add(GTK_CONTAINER(osParent), GTK_WIDGET(c->Internal)); + // make it visible by default + gtk_widget_show_all(GTK_WIDGET(c->Internal)); + // hold a reference to it to keep it alive + g_object_ref(G_OBJECT(c->Internal)); + return c; +} diff --git a/new/unix/uipriv_unix.h b/new/unix/uipriv_unix.h index 53f6a2e3..b9177de8 100644 --- a/new/unix/uipriv_unix.h +++ b/new/unix/uipriv_unix.h @@ -16,32 +16,3 @@ extern char *strdupText(const char *); // menu.c extern GtkWidget *makeMenubar(uiWindow *); - -// oscontainer.c -#define uipOSContainerType (uipOSContainer_get_type()) -#define uipOSContainer(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), uipOSContainerType, uipOSContainer)) -#define uipIsOSContainer(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), uipOSContainerType)) -#define uipOSContainerClass(class) (G_TYPE_CHECK_CLASS_CAST((class), uipOSContainerType, uipOSContainerClass)) -#define uipIsOSContainerClass(class) (G_TYPE_CHECK_CLASS_TYPE((class), uipOSContainer)) -#define uipGetParentClass(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), uipOSContainerType, uipOSContainerClass)) -typedef struct uipOSContainer uipOSContainer; -typedef struct uipOSContainerClass uipOSContainerClass; -struct uipOSContainer { - GtkContainer parent_instance; - // TODO make these private - uiControl *mainControl; - GPtrArray *children; // for forall() - intmax_t marginLeft; - intmax_t marginTop; - intmax_t marginRight; - intmax_t marginBottom; - gboolean canDestroy; -}; -struct uipOSContainerClass { - GtkContainerClass parent_class; -}; -extern GType uipOSContainer_get_type(void); -extern GtkWidget *newOSContainer(void); -extern void osContainerDestroy(uipOSContainer *); -extern void osContainerSetMainControl(uipOSContainer *, uiControl *); -extern void osContainerSetMargins(uipOSContainer *, intmax_t, intmax_t, intmax_t, intmax_t); diff --git a/new/unix/window.c b/new/unix/window.c index 6a050c4f..97a2477f 100644 --- a/new/unix/window.c +++ b/new/unix/window.c @@ -15,8 +15,8 @@ struct window { GtkBox *vbox; // the OS container for the uiWindow + uiOSContainer *content; GtkWidget *contentWidget; - uipOSContainer *content; // events int (*onClosing)(uiWindow *, void *); @@ -47,20 +47,13 @@ static void windowDestroy(uiWindow *ww) // first, hide the window to avoid flicker gtk_widget_hide(w->widget); - // next, remove the uiOSContainer from the vbox - // this will free the GtkWindow's reference to it gtk_container_remove(w->vboxcontainer, GTK_WIDGET(w->contentWidget)); - // next, destroy the uiOSContainer, which will destroy its child widget - // this will release its own reference. - osContainerDestroy(w->content); - + uiOSContainerDestroy(w->content); // TODO menus - // next, destroy the GtkWindow itself, which will destroy the vbox, menus, etc. gtk_widget_destroy(w->widget); - // finally, free ourselves uiFree(w); } @@ -113,7 +106,9 @@ static void windowSetChild(uiWindow *ww, uiControl *c) { struct window *w = (struct window *) ww; - osContainerSetMainControl(w->content, c); + // TODO make the update implicit + uiOSContainerSetMainControl(w->content, c); + uiOSContainerUpdate(w->content); } static int windowMargined(uiWindow *ww) @@ -130,9 +125,10 @@ static void windowSetMargined(uiWindow *ww, int margined) // TODO make the update implicit w->margined = margined; if (w->margined) - osContainerSetMargins(w->content, gtkXMargin, gtkYMargin, gtkXMargin, gtkYMargin); + uiOSContainerSetMargins(w->content, gtkXMargin, gtkYMargin, gtkXMargin, gtkYMargin); else - osContainerSetMargins(w->content, 0, 0, 0, 0); + uiOSContainerSetMargins(w->content, 0, 0, 0, 0); + uiOSContainerUpdate(w->content); } uiWindow *uiNewWindow(const char *title, int width, int height, int hasMenubar) @@ -145,10 +141,6 @@ uiWindow *uiNewWindow(const char *title, int width, int height, int hasMenubar) w->container = GTK_CONTAINER(w->widget); w->window = GTK_WINDOW(w->widget); - gtk_window_set_title(w->window, title); - // TODO this does not take menus into account - gtk_window_resize(w->window, width, height); - w->vboxwidget = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); w->vboxcontainer = GTK_CONTAINER(w->vboxwidget); w->vbox = GTK_BOX(w->vboxwidget); @@ -160,13 +152,12 @@ uiWindow *uiNewWindow(const char *title, int width, int height, int hasMenubar) gtk_container_add(w->vboxcontainer, makeMenubar(uiWindow(w))); // and add the OS container - w->contentWidget = newOSContainer(); - w->content = uipOSContainer(w->contentWidget); + w->content = uiNewOSContainer((uintptr_t) (w->vboxcontainer)); + w->contentWidget = GTK_WIDGET(uiOSContainerHandle(w->content)); gtk_widget_set_hexpand(w->contentWidget, TRUE); gtk_widget_set_halign(w->contentWidget, GTK_ALIGN_FILL); gtk_widget_set_vexpand(w->contentWidget, TRUE); gtk_widget_set_valign(w->contentWidget, GTK_ALIGN_FILL); - gtk_container_add(w->vboxcontainer, w->contentWidget); // show everything in the vbox, but not the GtkWindow itself gtk_widget_show_all(w->vboxwidget);