From: fliep <fliep@ddfedd41-794f-dd11-ae45-00112f111e67>
Date: Sun, 24 May 2009 13:08:33 +0000 (+0000)
Subject: Implemented evtype_Arrange events, fixing #8.
X-Git-Tag: v0.9~379
X-Git-Url: https://git.stderr.nl/gitweb?a=commitdiff_plain;h=549a3d9098e550a18ac0a9492a8c8ea2b6c1cf51;p=projects%2Fchimara%2Fchimara.git

Implemented evtype_Arrange events, fixing #8.
---

diff --git a/libchimara/chimara-glk-private.h b/libchimara/chimara-glk-private.h
index ba638a0..2cd928b 100644
--- a/libchimara/chimara-glk-private.h
+++ b/libchimara/chimara-glk-private.h
@@ -37,6 +37,9 @@ struct _ChimaraGlkPrivate {
     /* Abort mechanism */
     GMutex *abort_lock;
     gboolean abort_signalled;
+	/* Window arrangement locks */
+	GMutex *arrange_lock;
+	gboolean ignore_next_arrange_event;
     /* User-defined interrupt handler */
     void (*interrupt_handler)(void);
     /* Global tree of all windows */
diff --git a/libchimara/chimara-glk.c b/libchimara/chimara-glk.c
index 14931fb..1ddeb79 100644
--- a/libchimara/chimara-glk.c
+++ b/libchimara/chimara-glk.c
@@ -83,6 +83,8 @@ chimara_glk_init(ChimaraGlk *self)
     priv->event_queue_not_full = NULL;
     priv->abort_lock = NULL;
     priv->abort_signalled = FALSE;
+	priv->arrange_lock = NULL;
+	priv->ignore_next_arrange_event = FALSE;
     priv->interrupt_handler = NULL;
     priv->root_window = NULL;
     priv->fileref_list = NULL;
@@ -168,6 +170,13 @@ chimara_glk_finalize(GObject *object)
 	g_mutex_free(priv->abort_lock);
 	priv->abort_lock = NULL;
 
+	/* Free the window arrangement signalling */
+	g_mutex_lock(priv->arrange_lock);
+	/* Make sure no other thread is busy with this */
+	g_mutex_unlock(priv->arrange_lock);
+	g_mutex_free(priv->arrange_lock);
+	priv->arrange_lock = NULL;
+	
 	/* Free private data */
 	pango_font_description_free(priv->default_font_desc);
 	pango_font_description_free(priv->monospace_font_desc);
@@ -259,8 +268,10 @@ chimara_glk_size_request(GtkWidget *widget, GtkRequisition *requisition)
     }
 }
 
-/* Recursively give the Glk windows their allocated space */
-static void
+/* Recursively give the Glk windows their allocated space. Returns a window
+ containing all children of this window that must be redrawn, or NULL if there 
+ are no children that require redrawing. */
+static winid_t
 allocate_recurse(winid_t win, GtkAllocation *allocation, guint spacing)
 {
 	if(win->type == wintype_Pair)
@@ -347,8 +358,13 @@ allocate_recurse(winid_t win, GtkAllocation *allocation, guint spacing)
 		}
 		
 		/* Recurse */
-		allocate_recurse(win->window_node->children->data, &child1, spacing);
-		allocate_recurse(win->window_node->children->next->data, &child2, spacing);
+		winid_t arrange1 = allocate_recurse(win->window_node->children->data, &child1, spacing);
+		winid_t arrange2 = allocate_recurse(win->window_node->children->next->data, &child2, spacing);
+		if(arrange1 == NULL)
+			return arrange2;
+		if(arrange2 == NULL)
+			return arrange1;
+		return win;
 	}
 	
 	else if(win->type == wintype_TextGrid)
@@ -413,13 +429,15 @@ allocate_recurse(winid_t win, GtkAllocation *allocation, guint spacing)
 		    g_free(text);
 		}
 	
+		gboolean arrange = !(win->width == newwidth && win->height == newheight);
 		win->width = newwidth;
 		win->height = newheight;
+		return arrange? win : NULL;
 	}
 	
 	/* For non-pair, non-text-grid windows, just give them the size */
-	else
-		gtk_widget_size_allocate(win->frame, allocation);
+	gtk_widget_size_allocate(win->frame, allocation);
+	return NULL;
 }
 
 /* Overrides gtk_widget_size_allocate */
@@ -440,7 +458,19 @@ chimara_glk_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
 		child.y = allocation->y + GTK_CONTAINER(widget)->border_width;
 		child.width = CLAMP(allocation->width - 2 * GTK_CONTAINER(widget)->border_width, 0, allocation->width);
 		child.height = CLAMP(allocation->height - 2 * GTK_CONTAINER(widget)->border_width, 0, allocation->height);
-		allocate_recurse(priv->root_window->data, &child, priv->spacing);
+		winid_t arrange = allocate_recurse(priv->root_window->data, &child, priv->spacing);
+		
+		/* arrange points to a window that contains all text grid and graphics
+		 windows which have been resized */
+		g_mutex_lock(priv->arrange_lock);
+		if(!priv->ignore_next_arrange_event)
+		{
+			if(arrange)
+				event_throw(evtype_Arrange, arrange == priv->root_window->data? NULL : arrange, 0, 0);
+		}
+		else
+			priv->ignore_next_arrange_event = FALSE;
+		g_mutex_unlock(priv->arrange_lock);
 	}
 }
 
@@ -631,6 +661,7 @@ chimara_glk_new(void)
     priv->event_queue_not_empty = g_cond_new();
     priv->event_queue_not_full = g_cond_new();
     priv->abort_lock = g_mutex_new();
+	priv->arrange_lock = g_mutex_new();
     
     return GTK_WIDGET(self);
 }
diff --git a/libchimara/window.c b/libchimara/window.c
index 8b69531..84bc75d 100644
--- a/libchimara/window.c
+++ b/libchimara/window.c
@@ -561,7 +561,10 @@ glk_window_open(winid_t split, glui32 method, glui32 size, glui32 wintype,
 		glk_data->root_window = win->window_node;
 	}
 
-	/* Set the window as a child of the Glk widget */
+	/* Set the window as a child of the Glk widget, don't trigger an arrange event */
+	g_mutex_lock(glk_data->arrange_lock);
+	glk_data->ignore_next_arrange_event = TRUE;
+	g_mutex_unlock(glk_data->arrange_lock);
 	gtk_widget_set_parent(win->frame, GTK_WIDGET(glk_data->self));
 	gtk_widget_queue_resize(GTK_WIDGET(glk_data->self));
 	
@@ -603,23 +606,19 @@ remove_key_windows(GNode *node, winid_t closing_win)
 }
 
 /* Internal function: destroy this window's GTK widgets, window streams, 
- and those of all its children */
+ and those of all its children. GDK threads must be locked. */
 static void
 destroy_windows_below(winid_t win, stream_result_t *result)
 {
 	switch(win->type)
 	{
 		case wintype_Blank:
-			gdk_threads_enter();
 			gtk_widget_unparent(win->widget);
-			gdk_threads_leave();
 			break;
 	
 	    case wintype_TextGrid:
 		case wintype_TextBuffer:
-			gdk_threads_enter();
 			gtk_widget_unparent(win->frame);
-			gdk_threads_leave();
 			/* TODO: Cancel all input requests */
 			break;
 
@@ -714,6 +713,8 @@ glk_window_close(winid_t win, stream_result_t *result)
 {
 	VALID_WINDOW(win, return);
 	
+	gdk_threads_enter(); /* Prevent redraw while we're trashing the window */
+	
 	/* If any pair windows have this window or its children as a key window,
 	 set their key window to NULL */
 	g_node_traverse(glk_data->root_window, G_IN_ORDER, G_TRAVERSE_NON_LEAVES, -1, (GNodeTraverseFunc)remove_key_windows, win);
@@ -770,9 +771,10 @@ glk_window_close(winid_t win, stream_result_t *result)
 	g_free(win);
 
 	/* Schedule a redraw */
-	gdk_threads_enter();
+	g_mutex_lock(glk_data->arrange_lock);
+	glk_data->ignore_next_arrange_event = TRUE;
+	g_mutex_unlock(glk_data->arrange_lock);
 	gtk_widget_queue_resize( GTK_WIDGET(glk_data->self) );
-	gdk_window_process_all_updates();
 	gdk_threads_leave();
 }
 
@@ -1129,8 +1131,10 @@ glk_window_set_arrangement(winid_t win, glui32 method, glui32 size, winid_t keyw
 
 	/* Tell GTK to rearrange the windows */
 	gdk_threads_enter();
+	g_mutex_lock(glk_data->arrange_lock);
+	glk_data->ignore_next_arrange_event = TRUE;
+	g_mutex_unlock(glk_data->arrange_lock);
 	gtk_widget_queue_resize(GTK_WIDGET(glk_data->self));
-	gdk_window_process_all_updates();
 	gdk_threads_leave();
 }