]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkapplication.c
treeview: Add _gtk_rbtree_node_get_index()
[~andy/gtk] / gtk / gtkapplication.c
index cf57bf28f5202d6de11b7bc1979e7e65603da75c..377f104174571fca73c601b71ff30ad4446f22cf 100644 (file)
@@ -29,8 +29,8 @@
 
 #include "gtkapplication.h"
 #include "gtkmarshalers.h"
-#include "gtkwindow.h"
 #include "gtkmain.h"
+#include "gtkwindow.h"
 
 #include <gdk/gdk.h>
 #ifdef GDK_WINDOWING_X11
  * </example>
  */
 
+enum {
+  WINDOW_ADDED,
+  WINDOW_REMOVED,
+  LAST_SIGNAL
+};
+
+static guint gtk_application_signals[LAST_SIGNAL];
+
 G_DEFINE_TYPE (GtkApplication, gtk_application, G_TYPE_APPLICATION)
 
 struct _GtkApplicationPrivate
@@ -67,22 +75,32 @@ struct _GtkApplicationPrivate
   GList *windows;
 };
 
-static void
-gtk_application_startup (GApplication *application)
+static gboolean
+gtk_application_focus_in_event_cb (GtkWindow      *window,
+                                   GdkEventFocus  *event,
+                                   GtkApplication *application)
 {
-  gtk_init (0, 0);
-}
+  GtkApplicationPrivate *priv = application->priv;
+  GList *link;
 
-static void
-gtk_application_quit_mainloop (GApplication *application)
-{
-  gtk_main_quit ();
+  /* Keep the window list sorted by most-recently-focused. */
+  link = g_list_find (priv->windows, window);
+  if (link != NULL && link != priv->windows)
+    {
+      priv->windows = g_list_remove_link (priv->windows, link);
+      priv->windows = g_list_concat (link, priv->windows);
+    }
+
+  return FALSE;
 }
 
 static void
-gtk_application_run_mainloop (GApplication *application)
+gtk_application_startup (GApplication *application)
 {
-  gtk_main ();
+  G_APPLICATION_CLASS (gtk_application_parent_class)
+    ->startup (application);
+
+  gtk_init (0, 0);
 }
 
 static void
@@ -138,6 +156,36 @@ gtk_application_init (GtkApplication *application)
                                                    GtkApplicationPrivate);
 }
 
+static void
+gtk_application_window_added (GtkApplication *application,
+                              GtkWindow      *window)
+{
+  GtkApplicationPrivate *priv = application->priv;
+
+  priv->windows = g_list_prepend (priv->windows, window);
+  gtk_window_set_application (window, application);
+  g_application_hold (G_APPLICATION (application));
+
+  g_signal_connect (window, "focus-in-event",
+                    G_CALLBACK (gtk_application_focus_in_event_cb),
+                    application);
+}
+
+static void
+gtk_application_window_removed (GtkApplication *application,
+                                GtkWindow      *window)
+{
+  GtkApplicationPrivate *priv = application->priv;
+
+  g_signal_handlers_disconnect_by_func (window,
+                                        gtk_application_focus_in_event_cb,
+                                        application);
+
+  g_application_release (G_APPLICATION (application));
+  priv->windows = g_list_remove (priv->windows, window);
+  gtk_window_set_application (window, NULL);
+}
+
 static void
 gtk_application_class_init (GtkApplicationClass *class)
 {
@@ -148,10 +196,45 @@ gtk_application_class_init (GtkApplicationClass *class)
   application_class->after_emit = gtk_application_after_emit;
   application_class->startup = gtk_application_startup;
 
-  application_class->quit_mainloop = gtk_application_quit_mainloop;
-  application_class->run_mainloop = gtk_application_run_mainloop;
+  class->window_added = gtk_application_window_added;
+  class->window_removed = gtk_application_window_removed;
 
   g_type_class_add_private (class, sizeof (GtkApplicationPrivate));
+
+  /**
+   * GtkApplication::window-added:
+   * @application: the #GtkApplication which emitted the signal
+   * @window: the newly-added #GtkWindow
+   *
+   * Emitted when a #GtkWindow is added to @application through
+   * gtk_application_add_wi!ndow().
+   *
+   * Since: 3.2
+   */
+  gtk_application_signals[WINDOW_ADDED] =
+    g_signal_new ("window-added", GTK_TYPE_APPLICATION, G_SIGNAL_RUN_FIRST,
+                  G_STRUCT_OFFSET (GtkApplicationClass, window_added),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__OBJECT,
+                  G_TYPE_NONE, 1, GTK_TYPE_WINDOW);
+
+  /**
+   * GtkApplication::window-removed:
+   * @application: the #GtkApplication which emitted the signal
+   * @window: the #GtkWindow that is being removed
+   *
+   * Emitted when a #GtkWindow is removed from @application,
+   * either as a side-effect of being destroyed or explicitly
+   * through gtk_application_remove_window().
+   *
+   * Since: 3.2
+   */
+  gtk_application_signals[WINDOW_REMOVED] =
+    g_signal_new ("window-removed", GTK_TYPE_APPLICATION, G_SIGNAL_RUN_FIRST,
+                  G_STRUCT_OFFSET (GtkApplicationClass, window_removed),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__OBJECT,
+                  G_TYPE_NONE, 1, GTK_TYPE_WINDOW);
 }
 
 /**
@@ -205,18 +288,11 @@ void
 gtk_application_add_window (GtkApplication *application,
                             GtkWindow      *window)
 {
-  GtkApplicationPrivate *priv;
-
   g_return_if_fail (GTK_IS_APPLICATION (application));
 
-  priv = application->priv;
-
-  if (!g_list_find (priv->windows, window))
-    {
-      priv->windows = g_list_prepend (priv->windows, window);
-      gtk_window_set_application (window, application);
-      g_application_hold (G_APPLICATION (application));
-    }
+  if (!g_list_find (application->priv->windows, window))
+    g_signal_emit (application,
+                   gtk_application_signals[WINDOW_ADDED], 0, window);
 }
 
 /**
@@ -239,17 +315,11 @@ void
 gtk_application_remove_window (GtkApplication *application,
                                GtkWindow      *window)
 {
-  GtkApplicationPrivate *priv;
-
   g_return_if_fail (GTK_IS_APPLICATION (application));
 
-  priv = application->priv;
-  if (g_list_find (priv->windows, window))
-    {
-      priv->windows = g_list_remove (priv->windows, window);
-      g_application_release (G_APPLICATION (application));
-      gtk_window_set_application (window, NULL);
-    }
+  if (g_list_find (application->priv->windows, window))
+    g_signal_emit (application,
+                   gtk_application_signals[WINDOW_REMOVED], 0, window);
 }
 
 /**
@@ -258,7 +328,13 @@ gtk_application_remove_window (GtkApplication *application,
  *
  * Gets a list of the #GtkWindow<!-- -->s associated with @application.
  *
- * The list that is returned should not be modified in any way.
+ * The list is sorted by most recently focused window, such that the first
+ * element is the currently focused window.  (Useful for choosing a parent
+ * for a transient window.)
+ *
+ * The list that is returned should not be modified in any way. It will
+ * only remain valid until the next focus change or window creation or
+ * deletion.
  *
  * Returns: (element-type GtkWindow) (transfer none): a #GList of #GtkWindow
  *