Re: Muffling widget repaints



Hi Todd,

> This sounds like a very similar problem I'm having.  I'm curious if you 
> have some test case code that you could
> post?

My testing was all done within the context of my program, but I can try.  The
containers in question are WrapBox, which I've based on the GtkWrapBox class
from Gimp 2.0, and its subclass FileBox.

Here's most of the packing function, with the relevant changes commented.
Both this and the removal function are called with do_resize == FALSE during
the changeover.

void wrap_box_pack_pos(WrapBox* wbox, GtkWidget* child, guint pos,
	                   gboolean do_resize) {  /* This variable added. */
	WrapBoxChild* child_info;

	g_return_if_fail(IS_WRAP_BOX (wbox));
	g_return_if_fail(GTK_IS_WIDGET (child));
	g_return_if_fail(child->parent == NULL);

	child_info = g_new(WrapBoxChild, 1);
	child_info->widget = child;
	
	/* snipping out irrelevant child insertion code */

	gtk_widget_set_parent(child, GTK_WIDGET(wbox));

	if (GTK_WIDGET_REALIZED(wbox))
		gtk_widget_realize(child);

	if (GTK_WIDGET_VISIBLE(wbox) && GTK_WIDGET_VISIBLE(child)) {
		if (GTK_WIDGET_MAPPED(wbox))
			gtk_widget_map(child);

		if (do_resize)       /* This conditional added. */
			gtk_widget_queue_resize (child);
	}
}


And the removal function with a similar change:

void wrap_box_remove(GtkContainer* container, GtkWidget* widget,
	                  gboolean do_resize) {  /* This variable added. */
	WrapBox* wbox = WRAP_BOX(container);
	WrapBoxChild *child, *last = NULL;

	child = wbox->children;
	while (child) {
		if (child->widget == widget) {
			gboolean was_visible;

			was_visible = GTK_WIDGET_VISIBLE(widget);
			gtk_widget_unparent(widget);

			if (last)
				last->next = child->next;
			else
				wbox->children = child->next;
			g_free(child);
			wbox->n_children--;

			if (was_visible && do_resize)  /* && do_resize added here */
				gtk_widget_queue_resize(GTK_WIDGET (container));

			break;
		}

	last = child;
	child = last->next;
	}
}


In the initialization of the subclass object:

static void file_box_init(FileBox *fbox) {
	GTK_WIDGET_SET_FLAGS (fbox, GTK_NO_WINDOW);

	fbox->optimal_width = 0;
	fbox->show_hidden_files = FALSE;
	fbox->n_files = 0;
	fbox->file_max = 32767;
	fbox->file_display_limit = DEFAULT_FILE_DISPLAY_LIMIT;
	fbox->fi_slist = NULL;

	/* This class variable and the next line added. */
	fbox->eat_size_requests = FALSE;
	g_signal_connect(fbox, "size-request",
	                 G_CALLBACK(size_request_kludge), NULL);
}

And the callback function:

static gboolean size_request_kludge(GtkWidget* widget,
		GtkRequisition* requisition, gpointer data) {
	FileBox* fbox = FILE_BOX(widget);
	return fbox->eat_size_requests;
}


Then before entering the add/remove loop, this function is called with FALSE,
and then with TRUE afterward:

static void file_box_allow_size_requests(FileBox* fbox, gboolean allow) {

	if (fbox->eat_size_requests != allow)
		return;

	if (allow) {
		fbox->eat_size_requests = FALSE;
		gtk_widget_queue_resize(GTK_WIDGET(fbox));
		/* ^^^ This is the final size request, and the only one
		       to go through. */
	}
	else
		fbox->eat_size_requests = TRUE;
}


Hopefully that's clear and of some use.




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]