psppire-output-view: Only render output items once the window is realized.
authorBen Pfaff <blp@cs.stanford.edu>
Thu, 9 Oct 2014 05:39:18 +0000 (22:39 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Thu, 9 Oct 2014 05:39:18 +0000 (22:39 -0700)
Otherwise, in environments where the output view is not rendered
immediately upon the call to gtk_widget_show_all() from
psppire_output_submit(), psppire_output_view_put() called later in that
function would dereference a null pointer trying to create a rendering
from a null GTK_WIDGET (view->output)->window.

Bug #43362.

src/ui/gui/psppire-output-view.c
src/ui/gui/psppire-output-window.c

index 6b9445b404e6991ff097582b95e825d45394f4d2..3f254d7b63fb3e4b4b84496d604cd6df2dbc54fc 100644 (file)
@@ -194,7 +194,7 @@ rerender (struct psppire_output_view *view)
   struct output_view_item *item;
   cairo_t *cr;
 
-  if (!view->n_items)
+  if (!view->n_items || !GTK_WIDGET (view->output)->window)
     return;
 
   string_map_clear (&view->render_opts);
@@ -209,6 +209,7 @@ rerender (struct psppire_output_view *view)
     {
       struct xr_rendering *r;
       int tw, th;
+      bool new;
 
       if (view->y > 0)
         view->y += view->font_height / 2;
@@ -221,10 +222,18 @@ rerender (struct psppire_output_view *view)
         }
 
       xr_rendering_measure (r, &tw, &th);
+
+      new = !item->drawing_area;
+      if (new)
+        item->drawing_area = gtk_drawing_area_new ();
       g_object_set_data_full (G_OBJECT (item->drawing_area),
                               "rendering", r, free_rendering);
+
       gtk_widget_set_size_request (item->drawing_area, tw, th);
-      gtk_layout_move (view->output, item->drawing_area, 0, view->y);
+      if (new)
+        gtk_layout_put (view->output, item->drawing_area, 0, view->y);
+      else
+        gtk_layout_move (view->output, item->drawing_area, 0, view->y);
 
       if (view->max_width < tw)
         view->max_width = tw;
@@ -239,13 +248,14 @@ void
 psppire_output_view_put (struct psppire_output_view *view,
                          const struct output_item *item)
 {
+  struct output_view_item *view_item;
   GtkWidget *drawing_area;
   struct xr_rendering *r;
   struct string name;
   GtkTreeStore *store;
+  cairo_t *cr = NULL;
   GtkTreePath *path;
   GtkTreeIter iter;
-  cairo_t *cr;
   int tw, th;
 
   if (is_text_item (item))
@@ -266,33 +276,38 @@ psppire_output_view_put (struct psppire_output_view *view,
   if (view->n_items >= view->allocated_items)
     view->items = x2nrealloc (view->items, &view->allocated_items,
                                 sizeof *view->items);
-  view->items[view->n_items].item = output_item_ref (item);
-  view->items[view->n_items].drawing_area = drawing_area = gtk_drawing_area_new ();
-  view->n_items++;
+  view_item = &view->items[view->n_items++];
+  view_item->item = output_item_ref (item);
+  view_item->drawing_area = NULL;
 
-  cr = gdk_cairo_create (GTK_WIDGET (view->output)->window);
-  if (view->xr == NULL)
-    create_xr (view);
+  if (GTK_WIDGET (view->output)->window)
+    {
+      view_item->drawing_area = drawing_area = gtk_drawing_area_new ();
 
-  if (view->y > 0)
-    view->y += view->font_height / 2;
+      cr = gdk_cairo_create (GTK_WIDGET (view->output)->window);
+      if (view->xr == NULL)
+        create_xr (view);
 
-  r = xr_rendering_create (view->xr, item, cr);
-  if (r == NULL)
-    goto done;
+      if (view->y > 0)
+        view->y += view->font_height / 2;
+
+      r = xr_rendering_create (view->xr, item, cr);
+      if (r == NULL)
+        goto done;
 
-  xr_rendering_measure (r, &tw, &th);
+      xr_rendering_measure (r, &tw, &th);
 
-  g_object_set_data_full (G_OBJECT (drawing_area), "rendering", r, free_rendering);
-  g_signal_connect (drawing_area, "realize",
-                    G_CALLBACK (on_dwgarea_realize), view);
-  g_signal_connect (drawing_area, "expose_event",
-                    G_CALLBACK (expose_event_callback), view);
+      g_object_set_data_full (G_OBJECT (drawing_area), "rendering", r, free_rendering);
+      g_signal_connect (drawing_area, "realize",
+                        G_CALLBACK (on_dwgarea_realize), view);
+      g_signal_connect (drawing_area, "expose_event",
+                        G_CALLBACK (expose_event_callback), view);
 
-  gtk_widget_set_size_request (drawing_area, tw, th);
-  gtk_layout_put (view->output, drawing_area, 0, view->y);
+      gtk_widget_set_size_request (drawing_area, tw, th);
+      gtk_layout_put (view->output, drawing_area, 0, view->y);
 
-  gtk_widget_show (drawing_area);
+      gtk_widget_show (drawing_area);
+    }
 
   if (view->overview
       && (!is_text_item (item)
index 074f90a88be77477ac9d9f8e095b058801464fad..3c889808a32004551c08f45ec49b865a45d69c30 100644 (file)
@@ -139,17 +139,27 @@ psppire_output_submit (struct output_driver *this,
 {
   struct psppire_output_driver *pod = psppire_output_cast (this);
   PsppireOutputWindow *window;
+  bool new;
 
-  if (pod->window == NULL)
+  new = pod->window == NULL;
+  if (new)
     {
       pod->window = PSPPIRE_OUTPUT_WINDOW (psppire_output_window_new ());
-      gtk_widget_show_all (GTK_WIDGET (pod->window));
       pod->window->driver = pod;
     }
   window = pod->window;
 
   psppire_output_view_put (window->view, item);
 
+  if (new)
+    {
+      /* We could have called this earlier in the previous "if (new)" block,
+         but doing it here finds, in a plain GTK+ environment, a bug that
+         otherwise only showed up on an Ubuntu Unity desktop.  See bug
+         #43362. */
+      gtk_widget_show_all (GTK_WIDGET (pod->window));
+    }
+
   gtk_window_set_urgency_hint (GTK_WINDOW (pod->window), TRUE);
 }