Implemented evtype_Arrange events, fixing #8.
authorfliep <fliep@ddfedd41-794f-dd11-ae45-00112f111e67>
Sun, 24 May 2009 13:08:33 +0000 (13:08 +0000)
committerfliep <fliep@ddfedd41-794f-dd11-ae45-00112f111e67>
Sun, 24 May 2009 13:08:33 +0000 (13:08 +0000)
libchimara/chimara-glk-private.h
libchimara/chimara-glk.c
libchimara/window.c

index ba638a0e6e8496833c41f457ca1851ef73171023..2cd928b30bda44b28b0e2f4d31449881e8ed03dd 100644 (file)
@@ -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 */
index 14931fb8a265b065e62f850cb23d554d9c0b1333..1ddeb7911e8a859294f51de746597dbf81f726f1 100644 (file)
@@ -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);
 }
index 8b695315326629157e1dba292ca3b759818a0578..84bc75de088fdf584ba45cddd64dcd67baa47906 100644 (file)
@@ -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();
 }