changeset 13878:0d0ab1e39d0a

[gaim-migrate @ 16355] Change the behaviour of the widgets about how they update themselves. This makes things a little better, and hopefully easier to build more stuff on top of this. committer: Tailor Script <tailor@pidgin.im>
author Sadrul Habib Chowdhury <imadil@gmail.com>
date Tue, 27 Jun 2006 02:33:55 +0000
parents 765bbdf29d04
children b5ff22440a5b
files console/libgnt/gnt.h console/libgnt/gntbox.c console/libgnt/gntbox.h console/libgnt/gntbutton.c console/libgnt/gntentry.c console/libgnt/gntlabel.c console/libgnt/gntmain.c console/libgnt/gnttree.c console/libgnt/gntwidget.c console/libgnt/gntwidget.h
diffstat 10 files changed, 159 insertions(+), 53 deletions(-) [+]
line wrap: on
line diff
--- a/console/libgnt/gnt.h	Mon Jun 26 19:54:53 2006 +0000
+++ b/console/libgnt/gnt.h	Tue Jun 27 02:33:55 2006 +0000
@@ -11,3 +11,4 @@
 
 void gnt_screen_release(GntWidget *widget);
 
+void gnt_scree_update(GntWidget *widget);
--- a/console/libgnt/gntbox.c	Mon Jun 26 19:54:53 2006 +0000
+++ b/console/libgnt/gntbox.c	Tue Jun 27 02:33:55 2006 +0000
@@ -12,14 +12,10 @@
 gnt_box_draw(GntWidget *widget)
 {
 	GntBox *box = GNT_BOX(widget);
-	GList *iter;
 
-	for (iter = box->list; iter; iter = iter->next)
-	{
-		GntWidget *w = GNT_WIDGET(iter->data);
-		gnt_widget_draw(w);
-		overwrite(w->window, widget->window);
-	}
+	g_list_foreach(box->list, (GFunc)gnt_widget_draw, NULL);
+
+	gnt_box_sync_children(box);
 
 	if (box->title)
 	{
@@ -40,9 +36,6 @@
 		mvwprintw(widget->window, 0, pos, title);
 		g_free(title);
 	}
-	wrefresh(widget->window);
-
-	gnt_screen_occupy(widget);
 	
 	DEBUG;
 }
@@ -376,3 +369,16 @@
 		GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW);
 }
 
+void gnt_box_sync_children(GntBox *box)
+{
+	GList *iter;
+	GntWidget *widget = GNT_WIDGET(box);
+
+	for (iter = box->list; iter; iter = iter->next)
+	{
+		GntWidget *w = GNT_WIDGET(iter->data);
+		copywin(w->window, widget->window, 0, 0, w->priv.y - widget->priv.y, w->priv.x - widget->priv.x,
+					w->priv.height, w->priv.width, FALSE);
+	}
+}
+
--- a/console/libgnt/gntbox.h	Mon Jun 26 19:54:53 2006 +0000
+++ b/console/libgnt/gntbox.h	Tue Jun 27 02:33:55 2006 +0000
@@ -57,6 +57,8 @@
 
 void gnt_box_set_toplevel(GntBox *box, gboolean set);
 
+void gnt_box_sync_children(GntBox *box);
+
 G_END_DECLS
 
 #endif /* GNT_BOX_H */
--- a/console/libgnt/gntbutton.c	Mon Jun 26 19:54:53 2006 +0000
+++ b/console/libgnt/gntbutton.c	Tue Jun 27 02:33:55 2006 +0000
@@ -21,8 +21,6 @@
 	wbkgdset(widget->window, '\0' | COLOR_PAIR(type));
 	mvwprintw(widget->window, 1, 1, button->priv->text);
 
-	wrefresh(widget->window);
-
 	DEBUG;
 }
 
--- a/console/libgnt/gntentry.c	Mon Jun 26 19:54:53 2006 +0000
+++ b/console/libgnt/gntentry.c	Tue Jun 27 02:33:55 2006 +0000
@@ -22,8 +22,6 @@
 	if (stop < widget->priv.width)
 		mvwhline(widget->window, 0, stop, ENTRY_CHAR, widget->priv.width - stop);
 
-	wrefresh(widget->window);
-
 	DEBUG;
 }
 
--- a/console/libgnt/gntlabel.c	Mon Jun 26 19:54:53 2006 +0000
+++ b/console/libgnt/gntlabel.c	Tue Jun 27 02:33:55 2006 +0000
@@ -24,7 +24,6 @@
 
 	wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_NORMAL));
 	mvwprintw(widget->window, 0, 0, label->text);
-	wrefresh(widget->window);
 
 	DEBUG;
 }
--- a/console/libgnt/gntmain.c	Mon Jun 26 19:54:53 2006 +0000
+++ b/console/libgnt/gntmain.c	Tue Jun 27 02:33:55 2006 +0000
@@ -142,6 +142,8 @@
 
 	if (value == NULL)
 		return;
+	if (n->me == nu->me)
+		return;
 
 	if (n->me->priv.x + n->me->priv.width < nu->me->priv.x)
 		return;
@@ -153,15 +155,24 @@
 	if (nu->me->priv.y + nu->me->priv.height < n->me->priv.y)
 		return;
 
-	n->above = g_list_prepend(n->above, nu->me);
-	nu->below = g_list_prepend(nu->below, n->me);
+	n->above = g_list_prepend(n->above, nu);
+	nu->below = g_list_prepend(nu->below, n);
 }
 
 void gnt_screen_occupy(GntWidget *widget)
 {
-	/* XXX: what happens if this is called more than once for the same widget?
-	 *      perhaps _release first? */
-	GntNode *node = g_new0(GntNode, 1);
+	GntNode *node;
+
+	if (widget->parent)
+	{
+		while (widget->parent)
+			widget = widget->parent;
+	}
+	
+	if (g_hash_table_lookup(nodes, widget))
+		return;		/* XXX: perhaps _update instead? */
+
+	node = g_new0(GntNode, 1);
 	node->me = widget;
 
 	g_hash_table_foreach(nodes, check_intersection, node);
@@ -170,16 +181,21 @@
 
 void gnt_screen_release(GntWidget *widget)
 {
+	WINDOW *win;
 	GList *iter;
 	GntNode *node = g_hash_table_lookup(nodes, widget);
 	if (node == NULL || node->below == NULL)	/* Yay! Nothing to do. */
 		return;
 
+	win = dupwin(widget->window);
+	werase(win);
+
 	/* XXX: This is not going to work.
 	 *      It will be necessary to build a topology and go from there. */
 	for (iter = node->below; iter; iter = iter->next)
 	{
-		GntWidget *w = iter->data;
+		GntNode *n = iter->data;
+		GntWidget *w = n->me;
 		int left, right, top, bottom;
 
 		left = MAX(widget->priv.x, w->priv.x) - w->priv.x;
@@ -188,9 +204,61 @@
 		top = MAX(widget->priv.y, w->priv.y) - w->priv.y;
 		bottom = MIN(widget->priv.y + widget->priv.height, w->priv.y + w->priv.height) - w->priv.y;
 		
-		gnt_widget_expose(w, left, top, right - left, bottom - top);
+		copywin(w->window, win, top, left,
+						w->priv.y + top,
+						w->priv.x + left,
+						w->priv.y + bottom - top - 1,
+						w->priv.x + right - left - 1, FALSE);
+		n->above = g_list_remove(n->above, node);
 	}
 
+	wrefresh(win);
+	delwin(win);
+
 	g_hash_table_remove(nodes, widget);
 }
 
+void gnt_screen_update(GntWidget *widget)
+{
+	GList *iter;
+	WINDOW *win;
+	GntNode *node;
+	
+	if (widget->parent)
+	{
+		while (widget->parent)
+			widget = widget->parent;
+	}
+	
+	gnt_box_sync_children(widget);
+	node = g_hash_table_lookup(nodes, widget);
+
+	win = dupwin(widget->window);
+	
+	if (node && node->above)
+	{
+		/* XXX: Same here: need to build a topology first. */
+		for (iter = node->above; iter; iter = iter->next)
+		{
+			GntNode *n = iter->data;
+			GntWidget *w = n->me;
+			int left, right, top, bottom;
+
+			left = MAX(widget->priv.x, w->priv.x) - w->priv.x;
+			right = MIN(widget->priv.x + widget->priv.width, w->priv.x + w->priv.width) - w->priv.x;
+			
+			top = MAX(widget->priv.y, w->priv.y) - w->priv.y;
+			bottom = MIN(widget->priv.y + widget->priv.height, w->priv.y + w->priv.height) - w->priv.y;
+
+			copywin(w->window, win, top, left,
+					w->priv.y + top,
+					w->priv.x + left,
+					w->priv.y + bottom - top - 1,
+					w->priv.x + right - left - 1, FALSE);
+		}
+	}
+
+	wrefresh(win);
+	delwin(win);
+}
+
--- a/console/libgnt/gnttree.c	Mon Jun 26 19:54:53 2006 +0000
+++ b/console/libgnt/gnttree.c	Tue Jun 27 02:33:55 2006 +0000
@@ -219,7 +219,7 @@
 		start++;
 	}
 
-	wrefresh(widget->window);
+	gnt_widget_queue_update(widget);
 }
 
 static void
@@ -231,8 +231,6 @@
 	scrollok(widget->window, TRUE);
 	wsetscrreg(widget->window, 0, widget->priv.height - 1);
 
-	tree->top = tree->root;
-
 	redraw_tree(tree);
 	
 	DEBUG;
--- a/console/libgnt/gntwidget.c	Mon Jun 26 19:54:53 2006 +0000
+++ b/console/libgnt/gntwidget.c	Tue Jun 27 02:33:55 2006 +0000
@@ -219,8 +219,15 @@
 void
 gnt_widget_destroy(GntWidget *obj)
 {
+	int id;
 	g_return_if_fail(GNT_IS_WIDGET(obj));
 
+	if ((id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(obj), "gnt:queue_update"))))
+	{
+		g_source_remove(id);
+		g_object_set_data(G_OBJECT(obj), "gnt:queue_update", NULL);
+	}
+
 	gnt_widget_hide(obj);
 	delwin(obj->window);
 	if(!(GNT_WIDGET_FLAGS(obj) & GNT_WIDGET_DESTROYING))
@@ -244,24 +251,29 @@
 {
 	/* Draw the widget */
 	DEBUG;
-	if (!(GNT_WIDGET_FLAGS(widget) & GNT_WIDGET_MAPPED))
-		gnt_widget_map(widget);
+	if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_DRAWING))
+		return;
 
-	if (widget->window)
+	GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_DRAWING);
+	if (!(GNT_WIDGET_FLAGS(widget) & GNT_WIDGET_MAPPED))
 	{
-		delwin(widget->window);
+		gnt_widget_map(widget);
+		gnt_screen_occupy(widget);
 	}
-	
-	widget->window = newwin(widget->priv.height, widget->priv.width,
-					widget->priv.y, widget->priv.x);
-	wbkgd(widget->window, COLOR_PAIR(GNT_COLOR_NORMAL));
+
+	if (widget->window == NULL)
+	{
+		/* XXX: It may be necessary to make sure the size hasn't changed */
+		widget->window = newwin(widget->priv.height, widget->priv.width,
+						widget->priv.y, widget->priv.x);
+		wbkgd(widget->window, COLOR_PAIR(GNT_COLOR_NORMAL));
+	}
+
 	if (!(GNT_WIDGET_FLAGS(widget) & GNT_WIDGET_NO_BORDER))
-	{
 		box(widget->window, 0, 0);
-	}
 	else
 		werase(widget->window);
-
+	
 #if 0
 	/* XXX: No shadow for now :( */
 	if (!(GNT_WIDGET_FLAGS(widget) & GNT_WIDGET_NO_SHADOW))
@@ -276,10 +288,12 @@
 		touchline(widget->back, 0, widget->priv.height);
 		wrefresh(widget->back);
 	}
-#endif
 
 	wrefresh(widget->window);
+#endif
 	g_signal_emit(widget, signals[SIG_DRAW], 0);
+	gnt_widget_queue_update(widget);
+	GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_DRAWING);
 }
 
 gboolean
@@ -301,16 +315,9 @@
 void
 gnt_widget_hide(GntWidget *widget)
 {
-	int i;
-
-	/* XXX: Currently it simply empties the window. Ideally, it will
-	 * detect what windows are immediately beneath this one, and cause
-	 * those windows to redraw themselves by emitting the approrpiate
-	 * expose signal. */
-
 	wbkgdset(widget->window, '\0' | COLOR_PAIR(GNT_COLOR_NORMAL));
 	werase(widget->window);
-	wrefresh(widget->window);
+	gnt_screen_release(widget);
 }
 
 void
@@ -387,3 +394,27 @@
 	g_signal_emit(widget, signals[SIG_ACTIVATE], 0);
 }
 
+static gboolean
+update_queue_callback(gpointer data)
+{
+	GntWidget *widget = GNT_WIDGET(data);
+
+	if (!g_object_get_data(G_OBJECT(widget), "gnt:queue_update"))
+		return FALSE;
+	gnt_screen_update(widget);
+	g_object_set_data(G_OBJECT(widget), "gnt:queue_update", GINT_TO_POINTER(FALSE));
+	return FALSE;
+}
+
+void gnt_widget_queue_update(GntWidget *widget)
+{
+	while (widget->parent)
+		widget = widget->parent;
+	
+	if (!g_object_get_data(G_OBJECT(widget), "gnt:queue_update"))
+	{
+		int id = g_timeout_add(0, update_queue_callback, widget);
+		g_object_set_data(G_OBJECT(widget), "gnt:queue_update", GINT_TO_POINTER(id));
+	}
+}
+
--- a/console/libgnt/gntwidget.h	Mon Jun 26 19:54:53 2006 +0000
+++ b/console/libgnt/gntwidget.h	Tue Jun 27 02:33:55 2006 +0000
@@ -17,8 +17,7 @@
 #define GNT_WIDGET_SET_FLAGS(obj, flags)		(GNT_WIDGET_FLAGS(obj) |= flags)
 #define GNT_WIDGET_UNSET_FLAGS(obj, flags)	(GNT_WIDGET_FLAGS(obj) &= ~(flags))
 #define GNT_WIDGET_IS_FLAG_SET(obj, flags)	(GNT_WIDGET_FLAGS(obj) & (flags))
-#define	DEBUG
-//#define	DEBUG	printf("%s\n", __FUNCTION__)
+#define	DEBUG	fprintf(stderr, "%s\n", __FUNCTION__)
 
 typedef struct _GnWidget			GntWidget;
 typedef struct _GnWidgetPriv		GntWidgetPriv;
@@ -28,16 +27,18 @@
 
 typedef enum _GnWidgetFlags
 {
-	GNT_WIDGET_DESTROYING	= 1 << 0,
-	GNT_WIDGET_CAN_TAKE_FOCUS= 1 << 1,
-	GNT_WIDGET_MAPPED 		= 1 << 2,
+	GNT_WIDGET_DESTROYING     = 1 << 0,
+	GNT_WIDGET_CAN_TAKE_FOCUS = 1 << 1,
+	GNT_WIDGET_MAPPED         = 1 << 2,
 	/* XXX: Need to set the following two as properties, and setup a callback whenever these
 	 * get chnaged. */
-	GNT_WIDGET_NO_BORDER		= 1 << 3,
-	GNT_WIDGET_NO_SHADOW		= 1 << 4,
-	GNT_WIDGET_HAS_FOCUS		= 1 << 5
+	GNT_WIDGET_NO_BORDER      = 1 << 3,
+	GNT_WIDGET_NO_SHADOW      = 1 << 4,
+	GNT_WIDGET_HAS_FOCUS      = 1 << 5,
+	GNT_WIDGET_DRAWING        = 1 << 6
 } GntWidgetFlags;
 
+/* XXX: I'll have to ask grim what he's using this for in guifications. */
 typedef enum _GnParamFlags
 {
 	GNT_PARAM_SERIALIZABLE	= 1 << G_PARAM_USER_SHIFT
@@ -112,6 +113,10 @@
 
 void gnt_widget_set_name(GntWidget *widget, const char *name);
 
+/* Widget-subclasses should call this from the draw-callback.
+ * Applications should just call gnt_widget_draw instead of this. */
+void gnt_widget_queue_update(GntWidget *widget);
+
 G_END_DECLS
 
 #endif /* GNT_WIDGET_H */