diff --git a/build/GNUmakefile.example b/build/GNUmakefile.example index f2653865..31be42ca 100644 --- a/build/GNUmakefile.example +++ b/build/GNUmakefile.example @@ -37,6 +37,9 @@ ifeq ($(TOOLCHAIN),gcc) else LDFLAGS += -Wl,-rpath,'$$ORIGIN' endif + ifneq ($(findstring cpp-,$(EXAMPLE)),) + LDFLAGS += -pthread + endif else # TODO is there an equivalent to -L? LDFLAGS += $(OUTDIR)/libui.lib diff --git a/common/uipriv.h b/common/uipriv.h index e39bcf86..2c6756bd 100644 --- a/common/uipriv.h +++ b/common/uipriv.h @@ -19,7 +19,7 @@ extern void realbug(const char *file, const char *line, const char *func, const extern void _implbug(const char *file, const char *line, const char *func, const char *format, ...); #define implbug(...) _implbug(__FILE__, _ns(__LINE__), __func__, __VA_ARGS__) extern void _userbug(const char *file, const char *line, const char *func, const char *format, ...); -#define userbug(...) _implbug(__FILE__, _ns(__LINE__), __func__, __VA_ARGS__) +#define userbug(...) _userbug(__FILE__, _ns(__LINE__), __func__, __VA_ARGS__) // control.c extern uiControl *newControl(size_t size, uint32_t OSsig, uint32_t typesig, const char *typenamestr); diff --git a/darwin/alloc.m b/darwin/alloc.m index 9f0531ba..0ce46404 100644 --- a/darwin/alloc.m +++ b/darwin/alloc.m @@ -43,6 +43,7 @@ void uninitAlloc(void) [str appendString:[NSString stringWithFormat:@"%p %s\n", ptr, *TYPE(ptr)]]; } userbug("Some data was leaked; either you left a uiControl lying around or there's a bug in libui itself. Leaked data:\n%s", [str UTF8String]); + [str release]; } void *uiAlloc(size_t size, const char *type) diff --git a/darwin/area.m b/darwin/area.m index ada4ae6d..3caf1599 100644 --- a/darwin/area.m +++ b/darwin/area.m @@ -335,7 +335,7 @@ int sendAreaEvents(NSEvent *e) void uiAreaSetSize(uiArea *a, intmax_t width, intmax_t height) { if (!a->scrolling) - userbug("You cannot call uiAreaSetSize() on a non-scrolling uiArea. (uiArea: %p)", a); + userbug("You cannot call uiAreaSetSize() on a non-scrolling uiArea. (area: %p)", a); [a->area setFrameSize:NSMakeSize(width, height)]; } @@ -347,7 +347,7 @@ void uiAreaQueueRedrawAll(uiArea *a) void uiAreaScrollTo(uiArea *a, double x, double y, double width, double height) { if (!a->scrolling) - userbug("You cannot call uiAreaScrollTo() on a non-scrolling uiArea. (uiArea: %p)", a); + userbug("You cannot call uiAreaScrollTo() on a non-scrolling uiArea. (area: %p)", a); [a->area scrollRectToVisible:NSMakeRect(x, y, width, height)]; // don't worry about the return value; it just says whether scrolling was needed } diff --git a/darwin/debug.m b/darwin/debug.m index 87467add..de6d9406 100644 --- a/darwin/debug.m +++ b/darwin/debug.m @@ -9,7 +9,7 @@ void realbug(const char *file, const char *line, const char *func, const char *p NSString *formatted; str = [NSMutableString new]; - [str appendString:[NSString stringWithFormat:@"[libui] %s:%s:%s %s", file, line, func, prefix]]; + [str appendString:[NSString stringWithFormat:@"[libui] %s:%s:%s() %s", file, line, func, prefix]]; formatted = [[NSString alloc] initWithFormat:[NSString stringWithUTF8String:format] arguments:ap]; [str appendString:formatted]; [formatted release]; diff --git a/unix/GNUfiles.mk b/unix/GNUfiles.mk index 4987f177..ef83c13f 100644 --- a/unix/GNUfiles.mk +++ b/unix/GNUfiles.mk @@ -10,6 +10,7 @@ CFILES += \ unix/combobox.c \ unix/control.c \ unix/datetimepicker.c \ + unix/debug.c \ unix/draw.c \ unix/drawmatrix.c \ unix/drawpath.c \ diff --git a/unix/alloc.c b/unix/alloc.c index cb37fa10..3c43ee25 100644 --- a/unix/alloc.c +++ b/unix/alloc.c @@ -20,18 +20,27 @@ void initAlloc(void) static void uninitComplain(gpointer ptr, gpointer data) { - fprintf(stderr, "[libui] %p %s\n", ptr, *TYPE(ptr)); + char **str = (char **) data; + char *str2; + + if (*str == NULL) + *str = g_strdup_printf(""); + str2 = g_strdup_printf("%s%p %s\n", *str, ptr, *TYPE(ptr)); + g_free(*str); + *str = str2; } void uninitAlloc(void) { + char *str = NULL; + if (allocations->len == 0) { g_ptr_array_free(allocations, TRUE); return; } - fprintf(stderr, "[libui] leaked allocations:\n"); - g_ptr_array_foreach(allocations, uninitComplain, NULL); - complain("either you left something around or there's a bug in libui"); + g_ptr_array_foreach(allocations, uninitComplain, &str); + userbug("Some data was leaked; either you left a uiControl lying around or there's a bug in libui itself. Leaked data:\n%s", str); + g_free(str); } void *uiAlloc(size_t size, const char *type) @@ -59,7 +68,7 @@ void *uiRealloc(void *p, size_t new, const char *type) memset(((uint8_t *) DATA(out)) + *s, 0, new - *s); *s = new; if (g_ptr_array_remove(allocations, p) == FALSE) - complain("%p not found in allocations array in uiRealloc()", p); + implbug("%p not found in allocations array in uiRealloc()", p); g_ptr_array_add(allocations, out); return DATA(out); } @@ -67,9 +76,9 @@ void *uiRealloc(void *p, size_t new, const char *type) void uiFree(void *p) { if (p == NULL) - complain("attempt to uiFree(NULL); there's a bug somewhere"); + implbug("attempt to uiFree(NULL); there's a bug somewhere"); p = BASE(p); g_free(p); if (g_ptr_array_remove(allocations, p) == FALSE) - complain("%p not found in allocations array in uiFree()", p); + implbug("%p not found in allocations array in uiFree()", p); } diff --git a/unix/area.c b/unix/area.c index ee4e081c..3a420f00 100644 --- a/unix/area.c +++ b/unix/area.c @@ -485,7 +485,7 @@ uiUnixControlAllDefaults(uiArea) void uiAreaSetSize(uiArea *a, intmax_t width, intmax_t height) { if (!a->scrolling) - complain("attempt to call uiAreaSetSize() on a non-scrolling uiArea"); + userbug("You cannot call uiAreaSetSize() on a non-scrolling uiArea. (area: %p)", a); a->scrollWidth = width; a->scrollHeight = height; gtk_widget_queue_resize(a->areaWidget); diff --git a/unix/debug.c b/unix/debug.c new file mode 100644 index 00000000..20a4e2d0 --- /dev/null +++ b/unix/debug.c @@ -0,0 +1,14 @@ +// 13 may 2016 +#include "uipriv_unix.h" + +// TODO don't halt on release builds + +void realbug(const char *file, const char *line, const char *func, const char *prefix, const char *format, va_list ap) +{ + char *a, *b; + + a = g_strdup_printf("[libui] %s:%s:%s() %s", file, line, func, prefix); + b = g_strdup_vprintf(format, ap); + g_critical("%s%s", a, b); + G_BREAKPOINT(); +} diff --git a/unix/draw.c b/unix/draw.c index 388de7be..2d7a6367 100644 --- a/unix/draw.c +++ b/unix/draw.c @@ -37,7 +37,7 @@ static cairo_pattern_t *mkbrush(uiDrawBrush *b) // case uiDrawBrushTypeImage: } if (cairo_pattern_status(pat) != CAIRO_STATUS_SUCCESS) - complain("error creating pattern in mkbrush(): %s", + implbug("error creating pattern in mkbrush(): %s", cairo_status_to_string(cairo_pattern_status(pat))); switch (b->Type) { case uiDrawBrushTypeLinearGradient: diff --git a/unix/drawpath.c b/unix/drawpath.c index 1204315b..acfcc953 100644 --- a/unix/drawpath.c +++ b/unix/drawpath.c @@ -43,7 +43,7 @@ void uiDrawFreePath(uiDrawPath *p) static void add(uiDrawPath *p, struct piece *piece) { if (p->ended) - complain("path ended in add()"); + userbug("You cannot modify a uiDrawPath that has been ended. (path: %p)", p); g_array_append_vals(p->pieces, piece, 1); } @@ -145,7 +145,7 @@ void runPath(uiDrawPath *p, cairo_t *cr) void (*arc)(cairo_t *, double, double, double, double, double); if (!p->ended) - complain("path not ended in runPath()"); + userbug("You cannot draw with a uiDrawPath that has not been ended. (path: %p)", p); cairo_new_path(cr); for (i = 0; i < p->pieces->len; i++) { piece = &g_array_index(p->pieces, struct piece, i); diff --git a/unix/menu.c b/unix/menu.c index cf276dac..5ccb4a51 100644 --- a/unix/menu.c +++ b/unix/menu.c @@ -109,7 +109,7 @@ void uiMenuItemDisable(uiMenuItem *item) void uiMenuItemOnClicked(uiMenuItem *item, void (*f)(uiMenuItem *, uiWindow *, void *), void *data) { if (item->type == typeQuit) - complain("attempt to call uiMenuItemOnClicked() on a Quit item; use uiOnShouldQuit() instead"); + userbug("You cannot call uiMenuItemOnClicked() on a Quit item; use uiOnShouldQuit() instead."); item->onClicked = f; item->onClickedData = data; } @@ -135,7 +135,7 @@ static uiMenuItem *newItem(uiMenu *m, int type, const char *name) uiMenuItem *item; if (menusFinalized) - complain("attempt to create a new menu item after menus have been finalized"); + userbug("You cannot create a new menu item after menus have been finalized."); item = uiNew(uiMenuItem); @@ -196,7 +196,7 @@ uiMenuItem *uiMenuAppendCheckItem(uiMenu *m, const char *name) uiMenuItem *uiMenuAppendQuitItem(uiMenu *m) { if (hasQuit) - complain("attempt to add multiple Quit menu items"); + userbug("You cannot have multiple Quit menu items in the same program."); hasQuit = TRUE; newItem(m, typeSeparator, NULL); return newItem(m, typeQuit, NULL); @@ -205,7 +205,7 @@ uiMenuItem *uiMenuAppendQuitItem(uiMenu *m) uiMenuItem *uiMenuAppendPreferencesItem(uiMenu *m) { if (hasPreferences) - complain("attempt to add multiple Preferences menu items"); + userbug("You cannot have multiple Preferences menu items in the same program."); hasPreferences = TRUE; newItem(m, typeSeparator, NULL); return newItem(m, typePreferences, NULL); @@ -214,7 +214,7 @@ uiMenuItem *uiMenuAppendPreferencesItem(uiMenu *m) uiMenuItem *uiMenuAppendAboutItem(uiMenu *m) { if (hasAbout) - complain("attempt to add multiple About menu items"); + userbug("You cannot have multiple About menu items in the same program."); hasAbout = TRUE; newItem(m, typeSeparator, NULL); return newItem(m, typeAbout, NULL); @@ -230,7 +230,7 @@ uiMenu *uiNewMenu(const char *name) uiMenu *m; if (menusFinalized) - complain("attempt to create a new menu after menus have been finalized"); + userbug("You cannot create a new menu after menus have been finalized."); if (menus == NULL) menus = g_array_new(FALSE, TRUE, sizeof (uiMenu *)); @@ -308,7 +308,7 @@ static void freeMenuItem(GtkWidget *widget, gpointer data) item = g_array_index(fmi->items, uiMenuItem *, fmi->i); w = (struct menuItemWindow *) g_hash_table_lookup(item->windows, widget); if (g_hash_table_remove(item->windows, widget) == FALSE) - complain("GtkMenuItem %p not in menu item's item/window map", widget); + implbug("GtkMenuItem %p not in menu item's item/window map", widget); uiFree(w); fmi->i++; } @@ -353,7 +353,8 @@ void uninitMenus(void) for (j = 0; j < m->items->len; j++) { item = g_array_index(m->items, uiMenuItem *, j); if (g_hash_table_size(item->windows) != 0) - complain("menu item %p (%s) still has uiWindows attached; did you forget to destroy some windows?", item, item->name); + // TODO is this really a userbug()? + implbug("menu item %p (%s) still has uiWindows attached; did you forget to destroy some windows?", item, item->name); g_free(item->name); g_hash_table_destroy(item->windows); uiFree(item); diff --git a/unix/progressbar.c b/unix/progressbar.c index 587bc8ad..40306e6c 100644 --- a/unix/progressbar.c +++ b/unix/progressbar.c @@ -12,7 +12,7 @@ uiUnixControlAllDefaults(uiProgressBar) void uiProgressBarSetValue(uiProgressBar *p, int value) { if (value < 0 || value > 100) - complain("value %d out of range in progressbarSetValue()", value); + userbug("Value %d is out of range for a uiProgressBar.", value); gtk_progress_bar_set_fraction(p->pbar, ((gdouble) value) / 100); } diff --git a/unix/spinbox.c b/unix/spinbox.c index 0f1a4f5e..433c3965 100644 --- a/unix/spinbox.c +++ b/unix/spinbox.c @@ -49,8 +49,9 @@ uiSpinbox *uiNewSpinbox(intmax_t min, intmax_t max) { uiSpinbox *s; + // TODO just swap? if (min >= max) - complain("error: min >= max in uiNewSpinbox()"); + userbug("min >= max not allowed in uiNewSpinbox()."); uiUnixNewControl(uiSpinbox, s); diff --git a/unix/util.c b/unix/util.c index 86d89a3e..7f4f43fb 100644 --- a/unix/util.c +++ b/unix/util.c @@ -1,17 +1,6 @@ // 18 april 2015 #include "uipriv_unix.h" -void complain(const char *fmt, ...) -{ - va_list ap; - char *msg; - - va_start(ap, fmt); - msg = g_strdup_vprintf(fmt, ap); - va_end(ap); - g_error("[libui] %s\n", msg); -} - void setMargined(GtkContainer *c, int margined) { if (margined)