+#if MDEBUG
+static int widget_count, container_count;
+
+static void count_callback(GtkWidget *w,
+ gpointer attribute((unused)) data) {
+ ++widget_count;
+ if(GTK_IS_CONTAINER(w)) {
+ ++container_count;
+ gtk_container_foreach(GTK_CONTAINER(w), count_callback, 0);
+ }
+}
+
+static void count_widgets(void) {
+ widget_count = 0;
+ container_count = 1;
+ if(toplevel)
+ gtk_container_foreach(GTK_CONTAINER(toplevel), count_callback, 0);
+ fprintf(stderr, "widget count: %8d container count: %8d\n",
+ widget_count, container_count);
+}
+#endif
+
+#if MTRACK
+const char *mtag = "init";
+static hash *mtrack_hash;
+
+static int *mthfind(const char *tag) {
+ static const int zero = 0;
+ int *cp = hash_find(mtrack_hash, tag);
+ if(!cp) {
+ hash_add(mtrack_hash, tag, &zero, HASH_INSERT);
+ cp = hash_find(mtrack_hash, tag);
+ }
+ return cp;
+}
+
+static void *trap_malloc(size_t n) {
+ void *ptr = malloc(n + sizeof(char *));
+
+ *(const char **)ptr = mtag;
+ ++*mthfind(mtag);
+ return (char *)ptr + sizeof(char *);
+}
+
+static void trap_free(void *ptr) {
+ const char *tag;
+ if(!ptr)
+ return;
+ ptr = (char *)ptr - sizeof(char *);
+ tag = *(const char **)ptr;
+ --*mthfind(tag);
+ free(ptr);
+}
+
+static void *trap_realloc(void *ptr, size_t n) {
+ if(!ptr)
+ return trap_malloc(n);
+ if(!n) {
+ trap_free(ptr);
+ return 0;
+ }
+ ptr = (char *)ptr - sizeof(char *);
+ ptr = realloc(ptr, n + sizeof(char *));
+ *(const char **)ptr = mtag;
+ return (char *)ptr + sizeof(char *);
+}
+
+static int report_tags_callback(const char *key, void *value,
+ void attribute((unused)) *u) {
+ fprintf(stderr, "%16s: %d\n", key, *(int *)value);
+ return 0;
+}
+
+static void report_tags(void) {
+ hash_foreach(mtrack_hash, report_tags_callback, 0);
+ fprintf(stderr, "\n");
+}
+
+static const GMemVTable glib_memvtable = {
+ trap_malloc,
+ trap_realloc,
+ trap_free,
+ 0,
+ 0,
+ 0
+};
+#endif
+