Implemented glk_window_get_size()
[rodin/chimara.git] / src / window.c
index db0af1a23b6a171c5c453d808f53e73d0e3956e4..1fed03d19165cc95b61a25fe61511932a228d3d3 100644 (file)
@@ -1,7 +1,7 @@
 #include "window.h"
+#include "chimara-glk-private.h"
 
-/* Global tree of all windows */
-static GNode *root_window = NULL;
+extern ChimaraGlkPrivate *glk_data;
 
 /**
  * glk_window_iterate:
@@ -25,7 +25,7 @@ glk_window_iterate(winid_t win, glui32 *rockptr)
        GNode *retnode;
        
        if(win == NULL)
-               retnode = root_window;
+               retnode = glk_data->root_window;
        else
        {
                GNode *node = win->window_node;
@@ -131,9 +131,9 @@ glk_window_get_sibling(winid_t win)
 winid_t
 glk_window_get_root()
 {
-       if(root_window == NULL)
+       if(glk_data->root_window == NULL)
                return NULL;
-       return (winid_t)root_window->data;
+       return (winid_t)glk_data->root_window->data;
 }
 
 /**
@@ -163,35 +163,27 @@ winid_t
 glk_window_open(winid_t split, glui32 method, glui32 size, glui32 wintype, 
                 glui32 rock)
 {
-       extern GtkBuilder *builder;
-
        if(split)
        {
                g_warning("glk_window_open: splitting of windows not implemented");
                return NULL;
        }
 
-       if(root_window != NULL)
+       if(glk_data->root_window != NULL)
        {
                g_warning("glk_window_open: there is already a window");
                return NULL;
        }
+       
+       gdk_threads_enter();
+       
        /* We only create one window and don't support any more than that */
        winid_t win = g_new0(struct glk_window_struct, 1);
-       root_window = g_node_new(win);
+       glk_data->root_window = g_node_new(win);
 
        win->rock = rock;
        win->type = wintype;
-
-       gdk_threads_enter();
-
-       GtkBox *vbox = GTK_BOX( gtk_builder_get_object(builder, "vbox") );                      
-       if(vbox == NULL)
-       {
-               error_dialog(NULL, NULL, "Could not find vbox");
-               gdk_threads_leave();
-               return NULL;
-       }
+    win->window_node = glk_data->root_window;
 
        switch(wintype)
        {
@@ -199,10 +191,13 @@ glk_window_open(winid_t split, glui32 method, glui32 size, glui32 wintype,
                {
                        /* A blank window will be a label without any text */
                        GtkWidget *label = gtk_label_new("");
-                       gtk_box_pack_end(vbox, label, TRUE, TRUE, 0);
                        gtk_widget_show(label);
                        
                        win->widget = label;
+                       win->frame = label;
+                       /* A blank window has no size */
+                       win->unit_width = 0;
+                       win->unit_height = 0;
                        /* You can print to a blank window's stream, but it does nothing */
                        win->window_stream = window_stream_new(win);
                        win->echo_stream = NULL;
@@ -219,10 +214,16 @@ glk_window_open(winid_t split, glui32 method, glui32 size, glui32 wintype,
                        gtk_text_view_set_editable( GTK_TEXT_VIEW(textview), FALSE );
 
                        gtk_container_add( GTK_CONTAINER(scrolledwindow), textview );
-                       gtk_box_pack_end(vbox, scrolledwindow, TRUE, TRUE, 0);
                        gtk_widget_show_all(scrolledwindow);
 
                        win->widget = textview;
+                       win->frame = scrolledwindow;
+                       /* Determine the size of a "0" character in pixels" */
+                       PangoLayout *zero = gtk_widget_create_pango_layout(textview, "0");
+                       pango_layout_get_pixel_size( zero, &(win->unit_width), &(win->unit_height) );
+                       g_object_unref(zero);
+                       
+                       /* Set the other parameters */
                        win->window_stream = window_stream_new(win);
                        win->echo_stream = NULL;
                        win->input_request_type = INPUT_REQUEST_NONE;
@@ -248,13 +249,17 @@ glk_window_open(winid_t split, glui32 method, glui32 size, glui32 wintype,
                        break;
                        
                default:
+                       gdk_threads_leave();
                        g_warning("%s: unsupported window type", __func__);
                        g_free(win);
-                       gdk_threads_leave();
+                       g_node_destroy(glk_data->root_window);
+                       glk_data->root_window = NULL;
                        return NULL;
        }
 
-       win->window_node = root_window;
+    /* Put the frame widget into our container */
+    gtk_widget_set_parent(win->frame, GTK_WIDGET(glk_data->self));
+    gtk_widget_queue_resize(GTK_WIDGET(glk_data->self));
 
        gdk_threads_leave();
 
@@ -461,17 +466,46 @@ glk_window_get_size(winid_t win, glui32 *widthptr, glui32 *heightptr)
 {
        g_return_if_fail(win != NULL);
 
-       /* TODO: Write this function */
-       /* For a text buffer window: Return the number of rows and columns which
-       would be available _if_ the window was filled with "0" (zero) characters in
-       the "normal" font. */
-       if(widthptr != NULL) {
-               *widthptr = 0;
-       }
-
-       if(heightptr != NULL) {
-               *heightptr = 0;
-       }
+    switch(win->type)
+    {
+        case wintype_Blank:
+            if(widthptr != NULL)
+                *widthptr = 0;
+            if(heightptr != NULL)
+                *heightptr = 0;
+            break;
+            
+        case wintype_TextBuffer:
+            /* TODO: Glk wants to be able to get its windows' sizes as soon as they are created, but GTK doesn't decide on their sizes until they are drawn. The drawing happens somewhere in an idle function. A good method would be to make an educated guess of the window's size using the ChimaraGlk widget's size. */
+            gdk_threads_enter();
+            /*if(win->widget->allocation.width == 1 && win->widget->allocation.height == 1)
+            {
+                g_warning("glk_window_get_size: The Glk program requested the size of a window before it was allocated screen space by GTK. The window size is just an educated guess.");
+                guess the size from the parent window;
+                break;
+            } */
+            
+            /* Instead, we wait for GTK to draw the widget. This is probably very slow and should be fixed. */
+            while(win->widget->allocation.width == 1 && win->widget->allocation.height == 1)
+            {
+                /* Release the GDK lock momentarily */
+                gdk_threads_leave();
+                gdk_threads_enter();
+                while(gtk_events_pending())
+                    gtk_main_iteration();
+            }
+                
+            if(widthptr != NULL)
+                *widthptr = (glui32)(win->widget->allocation.width / win->unit_width);
+            if(heightptr != NULL)
+                *heightptr = (glui32)(win->widget->allocation.height / win->unit_height);
+            gdk_threads_leave();
+            
+            break;
+            
+        default:
+            g_warning("glk_window_get_size: Unsupported window type");
+    }
 }
 
 /**