Properly free a GList and avoid potential memory corruption
[hildon] / hildon / hildon-window.c
index b68820a..1d5e3e0 100644 (file)
 
 /**
  * SECTION:hildon-window
- * @short_description: Widget representing a top-level window in the Hildon framework.
+ * @short_description: Top-level window in the Hildon framework.
  * @see_also: #HildonProgram, #HildonStackableWindow
  *
- * #HildonWindow is a GTK widget which represents a top-level
+ * #HildonWindow is a top-level
  * window in the Hildon framework. It is derived from #GtkWindow
  * and provides additional commodities specific to the Hildon
  * framework.
@@ -95,6 +95,7 @@
 #include                                        "hildon-app-menu-private.h"
 #include                                        "hildon-find-toolbar.h"
 #include                                        "hildon-defines.h"
+#include                                        "hildon-private.h"
 
 #define                                         _(String) gettext(String)
 
@@ -1165,7 +1166,7 @@ hildon_window_key_press_event                   (GtkWidget *widget,
         case HILDON_HARDKEY_ESC:
             if (!priv->escape_timeout)
             {
-                priv->escape_timeout = g_timeout_add 
+                priv->escape_timeout = gdk_threads_add_timeout
                     (HILDON_WINDOW_LONG_PRESS_TIME,
                      hildon_window_escape_timeout, widget);
             }
@@ -1342,6 +1343,41 @@ hildon_window_is_topmost_notify                 (HildonWindow *window)
     }
 }
 
+static void
+hildon_window_update_menu_flag (HildonWindow *self,
+                                gboolean is_app_menu)
+{
+    HildonWindowPrivate *priv;
+
+    priv = HILDON_WINDOW_GET_PRIVATE (self);
+
+    if (is_app_menu)
+    {
+        /* Change the menu flag only if there is no program or common
+           application menu. */
+        if (!priv->program ||
+            !hildon_program_get_common_app_menu (priv->program))
+        {
+            hildon_window_set_menu_flag (self, priv->app_menu != NULL &&
+                                         hildon_app_menu_has_visible_children (priv->app_menu));
+        }
+    } else {
+        if (!priv->program || !hildon_program_get_common_menu (priv->program))
+        {
+            GList *menu_children = gtk_container_get_children (GTK_CONTAINER (priv->menu));
+            hildon_window_set_menu_flag (self, priv->menu != NULL && menu_children != NULL);
+            g_list_free (menu_children);
+        }
+    }
+}
+
+static void
+on_menu_changed (HildonAppMenu *menu,
+                 HildonWindow *window)
+{
+    hildon_window_update_menu_flag (window, TRUE);
+}
+
 /*
  * Sets the program to which the window belongs. This should only be called
  * by hildon_program_add_window
@@ -1694,8 +1730,6 @@ hildon_window_escape_timeout                    (gpointer data)
 
     g_assert (priv);
 
-    GDK_THREADS_ENTER ();
-
     /* Send fake event, simulation a situation that user
        pressed 'x' from the corner */
     event = gdk_event_new(GDK_DELETE);
@@ -1707,8 +1741,6 @@ hildon_window_escape_timeout                    (gpointer data)
 
     priv->escape_timeout = 0;
 
-    GDK_THREADS_LEAVE ();
-
     return FALSE;
 }
 
@@ -1962,6 +1994,25 @@ hildon_window_add_accel_group (HildonWindow *self,
     gtk_window_add_accel_group (GTK_WINDOW (self), accel_group);
 }
 
+static void
+do_set_has_menu (GtkWindow *window,
+                 gpointer   boolptr)
+{
+    gboolean has_menu = GPOINTER_TO_INT (boolptr);
+    hildon_gtk_window_set_clear_window_flag (window, "_HILDON_WM_WINDOW_MENU_INDICATOR",
+                                             XA_INTEGER, has_menu);
+    g_signal_handlers_disconnect_matched (window, G_SIGNAL_MATCH_FUNC,
+                                          0, 0, NULL, do_set_has_menu, NULL);
+}
+
+void
+hildon_window_set_menu_flag (HildonWindow *window,
+                             gboolean   has_menu)
+{
+    hildon_gtk_window_set_flag (GTK_WINDOW (window), (HildonFlagFunc) do_set_has_menu,
+                                GUINT_TO_POINTER (has_menu));
+}
+
 /**
  * hildon_window_set_main_menu:
  * @self: A #HildonWindow
@@ -2008,6 +2059,8 @@ hildon_window_set_main_menu (HildonWindow* self,
        if (accel_group != NULL)
            hildon_window_add_accel_group (self, accel_group);
     }
+
+    hildon_window_update_menu_flag (self, FALSE);
 }
 
 /**
@@ -2095,11 +2148,19 @@ hildon_window_set_app_menu                      (HildonWindow  *self,
     /* Add new menu */
     priv->app_menu = menu;
     if (menu)
+    {
         g_object_ref_sink (menu);
+        g_signal_connect (menu, "changed", G_CALLBACK (on_menu_changed), self);
+    }
 
     /* Unref old menu */
     if (old_menu)
+    {
+        g_signal_handlers_disconnect_by_func (old_menu, on_menu_changed, self);
         g_object_unref (old_menu);
+    }
+
+    hildon_window_update_menu_flag (self, TRUE);
 }
 
 /**