diff options
Diffstat (limited to 'new/unix')
| -rw-r--r-- | new/unix/alloc.c | 33 | ||||
| -rw-r--r-- | new/unix/button.c | 67 | ||||
| -rw-r--r-- | new/unix/checkbox.c | 89 | ||||
| -rw-r--r-- | new/unix/entry.c | 41 | ||||
| -rw-r--r-- | new/unix/init.c | 23 | ||||
| -rw-r--r-- | new/unix/label.c | 45 | ||||
| -rw-r--r-- | new/unix/main.c | 23 | ||||
| -rw-r--r-- | new/unix/newcontrol.c | 229 | ||||
| -rw-r--r-- | new/unix/parent.c | 183 | ||||
| -rw-r--r-- | new/unix/tab.c | 58 | ||||
| -rw-r--r-- | new/unix/util.c | 7 | ||||
| -rw-r--r-- | new/unix/window.c | 105 |
12 files changed, 903 insertions, 0 deletions
diff --git a/new/unix/alloc.c b/new/unix/alloc.c new file mode 100644 index 0000000..33482b2 --- /dev/null +++ b/new/unix/alloc.c @@ -0,0 +1,33 @@ +// 7 april 2015 +#include <stdio.h> +#include "uipriv_unix.h" + +void *uiAlloc(size_t size, const char *type) +{ + void *out; + + out = g_malloc0(size); + if (options.debugLogAllocations) + fprintf(stderr, "%p alloc %s\n", out, type); + return out; +} + +void *uiRealloc(void *p, size_t size, const char *type) +{ + void *out; + + if (p == NULL) + return uiAlloc(size, type); + // TODO fill with 0s + out = g_realloc(p, size); + if (options.debugLogAllocations) + fprintf(stderr, "%p realloc %p\n", p, out); + return out; +} + +void uiFree(void *p) +{ + g_free(p); + if (options.debugLogAllocations) + fprintf(stderr, "%p free\n", p); +} diff --git a/new/unix/button.c b/new/unix/button.c new file mode 100644 index 0000000..da09082 --- /dev/null +++ b/new/unix/button.c @@ -0,0 +1,67 @@ +// 7 april 2015 +#include "uipriv_unix.h" + +struct button { + void (*onClicked)(uiControl *, void *); + void *onClickedData; +}; + +static void onClicked(GtkButton *button, gpointer data) +{ + uiControl *c = (uiControl *) data; + struct button *b = (struct button *) (c->data); + + (*(b->onClicked))(c, b->onClickedData); +} + +static void defaultOnClicked(uiControl *c, void *data) +{ + // do nothing +} + +static void onDestroy(GtkWidget *widget, gpointer data) +{ + struct button *b = (struct button *) data; + + uiFree(b); +} + +uiControl *uiNewButton(const char *text) +{ + uiControl *c; + struct button *b; + GtkWidget *widget; + + c = uiUnixNewControl(GTK_TYPE_BUTTON, + FALSE, FALSE, + "label", text, + NULL); + + widget = GTK_WIDGET(uiControlHandle(c)); + g_signal_connect(widget, "clicked", G_CALLBACK(onClicked), c); + + b = uiNew(struct button); + g_signal_connect(widget, "destroy", G_CALLBACK(onDestroy), b); + b->onClicked = defaultOnClicked; + c->data = b; + + return c; +} + +char *uiButtonText(uiControl *c) +{ + return g_strdup(gtk_button_get_label(GTK_BUTTON(uiControlHandle(c)))); +} + +void uiButtonSetText(uiControl *c, const char *text) +{ + gtk_button_set_label(GTK_BUTTON(uiControlHandle(c)), text); +} + +void uiButtonOnClicked(uiControl *c, void (*f)(uiControl *, void *), void *data) +{ + struct button *b = (struct button *) (c->data); + + b->onClicked = f; + b->onClickedData = data; +} diff --git a/new/unix/checkbox.c b/new/unix/checkbox.c new file mode 100644 index 0000000..ddf9eda --- /dev/null +++ b/new/unix/checkbox.c @@ -0,0 +1,89 @@ +// 7 april 2015 +#include "uipriv_unix.h" + +struct checkbox { + void (*onToggled)(uiControl *, void *); + void *onToggledData; + gulong onToggledSignal; +}; + +static void onToggled(GtkToggleButton *b, gpointer data) +{ + uiControl *c = (uiControl *) data; + struct checkbox *cc = (struct checkbox *) (c->data); + + (*(cc->onToggled))(c, cc->onToggledData); +} + +static void defaultOnToggled(uiControl *c, void *data) +{ + // do nothing +} + +static void onDestroy(GtkWidget *widget, gpointer data) +{ + struct checkbox *cc = (struct checkbox *) data; + + uiFree(cc); +} + +uiControl *uiNewCheckbox(const char *text) +{ + uiControl *c; + struct checkbox *cc; + GtkWidget *widget; + + c = uiUnixNewControl(GTK_TYPE_CHECK_BUTTON, + FALSE, FALSE, + "label", text, + NULL); + + widget = GTK_WIDGET(uiControlHandle(c)); + + cc = uiNew(struct checkbox); + g_signal_connect(widget, "destroy", G_CALLBACK(onDestroy), cc); + cc->onToggledSignal = g_signal_connect(widget, "toggled", G_CALLBACK(onToggled), c); + cc->onToggled = defaultOnToggled; + c->data = cc; + + return c; +} + +char *uiCheckboxText(uiControl *c) +{ + return g_strdup(gtk_button_get_label(GTK_BUTTON(uiControlHandle(c)))); +} + +void uiCheckboxSetText(uiControl *c, const char *text) +{ + gtk_button_set_label(GTK_BUTTON(uiControlHandle(c)), text); +} + +void uiCheckboxOnToggled(uiControl *c, void (*f)(uiControl *, void *), void *data) +{ + struct checkbox *cc = (struct checkbox *) (c->data); + + cc->onToggled = f; + cc->onToggledData = data; +} + +int uiCheckboxChecked(uiControl *c) +{ + return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(uiControlHandle(c))) != FALSE; +} + +void uiCheckboxSetChecked(uiControl *c, int checked) +{ + struct checkbox *cc = (struct checkbox *) (c->data); + GtkToggleButton *button; + gboolean active; + + active = FALSE; + if (checked) + active = TRUE; + // we need to inhibit sending of ::toggled because this WILL send a ::toggled otherwise + button = GTK_TOGGLE_BUTTON(uiControlHandle(c)); + g_signal_handler_block(button, cc->onToggledSignal); + gtk_toggle_button_set_active(button, active); + g_signal_handler_unblock(button, cc->onToggledSignal); +} diff --git a/new/unix/entry.c b/new/unix/entry.c new file mode 100644 index 0000000..43caea3 --- /dev/null +++ b/new/unix/entry.c @@ -0,0 +1,41 @@ +// 8 april 2015 +#include "uipriv_unix.h" + +struct entry { +}; + +static void onDestroy(GtkWidget *widget, gpointer data) +{ + struct entry *e = (struct entry *) data; + + uiFree(e); +} + +uiControl *uiNewEntry(void) +{ + uiControl *c; + struct entry *e; + GtkWidget *widget; + + c = uiUnixNewControl(GTK_TYPE_ENTRY, + FALSE, FALSE, + NULL); + + widget = GTK_WIDGET(uiControlHandle(c)); + + e = uiNew(struct entry); + g_signal_connect(widget, "destroy", G_CALLBACK(onDestroy), e); + c->data = e; + + return c; +} + +char *uiEntryText(uiControl *c) +{ + return g_strdup(gtk_entry_get_text(GTK_ENTRY(uiControlHandle(c)))); +} + +void uiEntrySetText(uiControl *c, const char *text) +{ + gtk_entry_set_text(GTK_ENTRY(uiControlHandle(c)), text); +} diff --git a/new/unix/init.c b/new/unix/init.c new file mode 100644 index 0000000..b10c05b --- /dev/null +++ b/new/unix/init.c @@ -0,0 +1,23 @@ +// 6 april 2015 +#include "uipriv_unix.h" + +uiInitOptions options; + +const char *uiInit(uiInitOptions *o) +{ + GError *err = NULL; + const char *msg; + + options = *o; + if (gtk_init_with_args(NULL, NULL, NULL, NULL, NULL, &err) == FALSE) { + msg = g_strdup(err->message); + g_error_free(err); + return msg; + } + return NULL; +} + +void uiFreeInitError(const char *err) +{ + g_free((gpointer) err); +} diff --git a/new/unix/label.c b/new/unix/label.c new file mode 100644 index 0000000..1f950d3 --- /dev/null +++ b/new/unix/label.c @@ -0,0 +1,45 @@ +// 11 april 2015 +#include "uipriv_unix.h" + +struct label { +}; + +static void onDestroy(GtkWidget *widget, gpointer data) +{ + struct label *l = (struct label *) data; + + uiFree(l); +} + +uiControl *uiNewLabel(const char *text) +{ + uiControl *c; + struct label *l; + GtkWidget *widget; + + c = uiUnixNewControl(GTK_TYPE_LABEL, + FALSE, FALSE, + "label", text, + "xalign", 0.0, // note: must be a float constant, otherwise the ... will turn it into an int and we get segfaults on some platforms (thanks ebassi in irc.gimp.net/#gtk+) + // TODO yalign 0? + NULL); + + widget = GTK_WIDGET(uiControlHandle(c)); + + l = uiNew(struct label); + g_signal_connect(widget, "destroy", G_CALLBACK(onDestroy), l); + c->data = l; + + return c; +} + +char *uiLabelText(uiControl *c) +{ + // TODO change g_strdup() to a wrapper function for export in ui_unix.h + return g_strdup(gtk_label_get_text(GTK_LABEL(uiControlHandle(c)))); +} + +void uiLabelSetText(uiControl *c, const char *text) +{ + gtk_label_set_text(GTK_LABEL(uiControlHandle(c)), text); +} diff --git a/new/unix/main.c b/new/unix/main.c new file mode 100644 index 0000000..10af782 --- /dev/null +++ b/new/unix/main.c @@ -0,0 +1,23 @@ +// 6 april 2015 +#include "uipriv_unix.h" + +// #qo pkg-config: gtk+-3.0 + +void uiMain(void) +{ + gtk_main(); +} + +// gtk_main_quit() may run immediately, or it may wait for other pending events; "it depends" (thanks mclasen in irc.gimp.net/#gtk+) +// PostQuitMessage() on Windows always waits, so we must do so too +// we'll do it by using an idle callback +static gboolean quit(gpointer data) +{ + gtk_main_quit(); + return FALSE; +} + +void uiQuit(void) +{ + gdk_threads_add_idle(quit, NULL); +} diff --git a/new/unix/newcontrol.c b/new/unix/newcontrol.c new file mode 100644 index 0000000..500798b --- /dev/null +++ b/new/unix/newcontrol.c @@ -0,0 +1,229 @@ +// 7 april 2015 +#include "uipriv_unix.h" + +typedef struct singleWidget singleWidget; + +struct singleWidget { + GtkWidget *widget; + GtkWidget *scrolledWindow; + GtkWidget *immediate; // the widget that is added to the parent container; either widget or scrolledWindow + uiParent *parent; + gboolean userHid; + gboolean containerHid; + gboolean userDisabled; + gboolean containerDisabled; +}; + +static void singleDestroy(uiControl *c) +{ + singleWidget *s = (singleWidget *) (c->internal); + + gtk_widget_destroy(s->immediate); +} + +static uintptr_t singleHandle(uiControl *c) +{ + singleWidget *s = (singleWidget *) (c->internal); + + return (uintptr_t) (s->widget); +} + +static void singleSetParent(uiControl *c, uiParent *parent) +{ + singleWidget *s = (singleWidget *) (c->internal); + uiParent *oldparent; + + oldparent = s->parent; + s->parent = parent; + if (oldparent != NULL) { + gtk_container_remove(GTK_CONTAINER(uiParentHandle(oldparent)), s->immediate); + uiParentUpdate(oldparent); + } + if (s->parent != NULL) { + gtk_container_add(GTK_CONTAINER(uiParentHandle(s->parent)), s->immediate); + uiParentUpdate(s->parent); + } +} + +static void singlePreferredSize(uiControl *c, uiSizing *d, intmax_t *width, intmax_t *height) +{ + singleWidget *s = (singleWidget *) (c->internal); + GtkRequisition natural; + + // use the natural size as the minimum size is an *absolute* minimum + // for example, if a label has ellipsizing on, it can be the width of the ellipses, not the text + // there is a warning about height-for-width sizing, but in my tests this isn't an issue + gtk_widget_get_preferred_size(s->widget, NULL, &natural); + *width = natural.width; + *height = natural.height; +} + +static void singleResize(uiControl *c, intmax_t x, intmax_t y, intmax_t width, intmax_t height, uiSizing *d) +{ + singleWidget *s = (singleWidget *) (c->internal); + GtkAllocation a; + + a.x = x; + a.y = y; + a.width = width; + a.height = height; + gtk_widget_size_allocate(s->immediate, &a); +} + +static int singleVisible(uiControl *c) +{ + singleWidget *s = (singleWidget *) (c->internal); + + if (s->userHid) + return 0; + return 1; +} + +static void singleShow(uiControl *c) +{ + singleWidget *s = (singleWidget *) (c->internal); + + s->userHid = FALSE; + if (!s->containerHid) { + gtk_widget_show_all(s->immediate); + if (s->parent != NULL) + uiParentUpdate(s->parent); + } +} + +static void singleHide(uiControl *c) +{ + singleWidget *s = (singleWidget *) (c->internal); + + s->userHid = TRUE; + gtk_widget_hide(s->immediate); + if (s->parent != NULL) + uiParentUpdate(s->parent); +} + +static void singleContainerShow(uiControl *c) +{ + singleWidget *s = (singleWidget *) (c->internal); + + s->containerHid = FALSE; + if (!s->userHid) { + gtk_widget_show_all(s->immediate); + if (s->parent != NULL) + uiParentUpdate(s->parent); + } +} + +static void singleContainerHide(uiControl *c) +{ + singleWidget *s = (singleWidget *) (c->internal); + + s->containerHid = TRUE; + gtk_widget_hide(s->immediate); + if (s->parent != NULL) + uiParentUpdate(s->parent); +} + +static void singleEnable(uiControl *c) +{ + singleWidget *s = (singleWidget *) (c->internal); + + s->userDisabled = FALSE; + if (!s->containerDisabled) + gtk_widget_set_sensitive(s->immediate, TRUE); +} + +static void singleDisable(uiControl *c) +{ + singleWidget *s = (singleWidget *) (c->internal); + + s->userDisabled = TRUE; + gtk_widget_set_sensitive(s->immediate, FALSE); +} + +static void singleContainerEnable(uiControl *c) +{ + singleWidget *s = (singleWidget *) (c->internal); + + s->containerDisabled = FALSE; + if (!s->userDisabled) + gtk_widget_set_sensitive(s->immediate, TRUE); +} + +static void singleContainerDisable(uiControl *c) +{ + singleWidget *s = (singleWidget *) (c->internal); + + s->containerDisabled = TRUE; + gtk_widget_set_sensitive(s->immediate, FALSE); +} + +static void onDestroy(GtkWidget *widget, gpointer data) +{ + uiControl *c = (uiControl *) data; + singleWidget *s = (singleWidget *) (c->internal); + + uiFree(s); + uiFree(c); +} + +uiControl *uiUnixNewControl(GType type, gboolean inScrolledWindow, gboolean scrolledWindowHasBorder, const char *firstProperty, ...) +{ + uiControl *c; + singleWidget *s; + va_list ap; + + s = uiNew(singleWidget); + + va_start(ap, firstProperty); + s->widget = GTK_WIDGET(g_object_new_valist(type, firstProperty, ap)); + va_end(ap); + s->immediate = s->widget; + + if (inScrolledWindow) { + s->scrolledWindow = gtk_scrolled_window_new(NULL, NULL); + if (!GTK_IS_SCROLLABLE(s->widget)) + gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(s->scrolledWindow), s->widget); + else + gtk_container_add(GTK_CONTAINER(s->scrolledWindow), s->widget); + if (scrolledWindowHasBorder) + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(s->scrolledWindow), GTK_SHADOW_IN); + s->immediate = s->scrolledWindow; + } + + // we need to keep an extra reference on the immediate widget + // this is so uiControlDestroy() can work regardless of when it is called and who calls it + // without this: + // - end user call works (only one ref) + // - call in uiContainer destructor fails (uiContainer ref freed) + // with this: + // - end user call works (shoudn't be in any container) + // - call in uiContainer works (both refs freed) + // this also ensures singleRemoveParent() works properly + g_object_ref_sink(s->immediate); + + c = uiNew(uiControl); + // assign s later; we still need it for one more thing + c->destroy = singleDestroy; + c->handle = singleHandle; + c->setParent = singleSetParent; + c->preferredSize = singlePreferredSize; + c->resize = singleResize; + c->visible = singleVisible; + c->show = singleShow; + c->hide = singleHide; + c->containerShow = singleContainerShow; + c->containerHide = singleContainerHide; + c->enable = singleEnable; + c->disable = singleDisable; + c->containerEnable = singleContainerEnable; + c->containerDisable = singleContainerDisable; + + // and let's free everything with the immediate widget + g_signal_connect(s->immediate, "destroy", G_CALLBACK(onDestroy), c); + + // finally, call gtk_widget_show_all() here to set the initial visibility of the widget + gtk_widget_show_all(s->immediate); + + c->internal = s; + return c; +} diff --git a/new/unix/parent.c b/new/unix/parent.c new file mode 100644 index 0000000..54d5d06 --- /dev/null +++ b/new/unix/parent.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(p), 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(p->children); + p->children = NULL; + } + if (p->child != NULL) { + uiControlDestroy(p->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(p)); + 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(p), allocation); + if (p->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(p->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(p->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_widget_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; +} diff --git a/new/unix/tab.c b/new/unix/tab.c new file mode 100644 index 0000000..dd69e4c --- /dev/null +++ b/new/unix/tab.c @@ -0,0 +1,58 @@ +// 12 april 2015 +#include "uipriv_unix.h" + +struct tab { + uiParent **pages; + uintmax_t len; + uintmax_t cap; +}; + +static void onDestroy(GtkWidget *widget, gpointer data) +{ + struct tab *t = (struct tab *) data; + + uiFree(t->pages); + uiFree(t); +} + +uiControl *uiNewTab(void) +{ + uiControl *c; + struct tab *t; + GtkWidget *widget; + + c = uiUnixNewControl(GTK_TYPE_NOTEBOOK, + FALSE, FALSE, + NULL); + + widget = GTK_WIDGET(uiControlHandle(c)); + + t = uiNew(struct tab); + g_signal_connect(widget, "destroy", G_CALLBACK(onDestroy), t); + c->data = t; + + return c; +} + +#define tabCapGrow 32 + +void uiTabAddPage(uiControl *c, const char *name, uiControl *child) +{ + struct tab *t = (struct tab *) (c->data); + GtkWidget *notebook; + uiParent *content; + + if (t->len >= t->cap) { + t->cap += tabCapGrow; + t->pages = (uiParent **) uiRealloc(t->pages, t->cap * sizeof (uiParent *), "uiParent *[]"); + } + + notebook = GTK_WIDGET(uiControlHandle(c)); + content = uiNewParent((uintptr_t) notebook); + uiParentSetChild(content, child); + uiParentUpdate(content); + gtk_notebook_set_tab_label_text(GTK_NOTEBOOK(notebook), GTK_WIDGET(uiParentHandle(content)), name); + + t->pages[t->len] = content; + t->len++; +} diff --git a/new/unix/util.c b/new/unix/util.c new file mode 100644 index 0000000..72b71df --- /dev/null +++ b/new/unix/util.c @@ -0,0 +1,7 @@ +// 9 april 2015 +#include "uipriv_unix.h" + +void uiFreeText(char *t) +{ + g_free(t); +} diff --git a/new/unix/window.c b/new/unix/window.c new file mode 100644 index 0000000..e3fe6f3 --- /dev/null +++ b/new/unix/window.c @@ -0,0 +1,105 @@ +// 6 april 2015 +#include "uipriv_unix.h" + +struct uiWindow { + GtkWidget *widget; + uiParent *content; + int (*onClosing)(uiWindow *, void *); + void *onClosingData; + int margined; +}; + +static gboolean onClosing(GtkWidget *win, GdkEvent *e, gpointer data) +{ + uiWindow *w = (uiWindow *) data; + + // return exact values just in case + if ((*(w->onClosing))(w, w->onClosingData)) + return FALSE; + return TRUE; +} + +static int defaultOnClosing(uiWindow *w, void *data) +{ + return 1; +} + +static void onDestroy(GtkWidget *widget, gpointer data) +{ + uiWindow *w = (uiWindow *) data; + + uiFree(w); +} + +uiWindow *uiNewWindow(char *title, int width, int height) +{ + uiWindow *w; + + w = uiNew(uiWindow); + w->widget = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(w->widget), title); + gtk_window_resize(GTK_WINDOW(w->widget), width, height); + g_signal_connect(w->widget, "delete-event", G_CALLBACK(onClosing), w); + g_signal_connect(w->widget, "destroy", G_CALLBACK(onDestroy), w); + w->content = uiNewParent((uintptr_t) (w->widget)); + w->onClosing = defaultOnClosing; + return w; +} + +void uiWindowDestroy(uiWindow *w) +{ + gtk_widget_destroy(w->widget); +} + +uintptr_t uiWindowHandle(uiWindow *w) +{ + return (uintptr_t) (w->widget); +} + +char *uiWindowTitle(uiWindow *w) +{ + return g_strdup(gtk_window_get_title(GTK_WINDOW(w->widget))); +} + +void uiWindowSetTitle(uiWindow *w, const char *title) +{ + gtk_window_set_title(GTK_WINDOW(w->widget), title); +} + +void uiWindowShow(uiWindow *w) +{ + // don't use gtk_widget_show_all(); that will override user hidden settings + gtk_widget_show(w->widget); +} + +void uiWindowHide(uiWindow *w) +{ + gtk_widget_hide(w->widget); +} + +void uiWindowOnClosing(uiWindow *w, int (*f)(uiWindow *, void *), void *data) +{ + w->onClosing = f; + w->onClosingData = data; +} + +void uiWindowSetChild(uiWindow *w, uiControl *c) +{ + uiParentSetChild(w->content, c); + uiParentUpdate(w->content); +} + +int uiWindowMargined(uiWindow *w) +{ + return w->margined; +} + +void uiWindowSetMargined(uiWindow *w, int margined) +{ + w->margined = margined; + if (w->margined) + uiParentSetMargins(w->content, gtkXMargin, gtkYMargin, gtkXMargin, gtkYMargin); + else + uiParentSetMargins(w->content, 0, 0, 0, 0); + uiParentUpdate(w->content); +} |
