]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkmain.c
filechooserbutton: Add tests for unselect_all()
[~andy/gtk] / gtk / gtkmain.c
index c0cdabd9c88ae32056d39de5ab9ae6a6dde5d4fd..64e06d5059b45b2585b3aef3c2c65ca5af3bc353 100644 (file)
@@ -59,8 +59,8 @@
  * int
  * main (int argc, char **argv)
  * {
- *   /* Initialize i18n support */
- *   gtk_set_locale ();
+ *   /* Initialize i18n support with bindtextdomain(), etc. */
+ *   ...
  *
  *   /* Initialize the widget set */
  *   gtk_init (&argc, &argv);
 #include "gtkwidgetprivate.h"
 #include "gtkwindowprivate.h"
 
-#include "a11y/gailutil.h"
+#include "a11y/gtkaccessibility.h"
 
 /* Private type definitions
  */
@@ -172,6 +172,7 @@ static const GDebugKey gtk_debug_keys[] = {
   {"printing", GTK_DEBUG_PRINTING},
   {"builder", GTK_DEBUG_BUILDER},
   {"size-request", GTK_DEBUG_SIZE_REQUEST},
+  {"no-css-cache", GTK_DEBUG_NO_CSS_CACHE}
 };
 #endif /* G_ENABLE_DEBUG */
 
@@ -668,9 +669,6 @@ gettext_initialization (void)
 #endif  
 }
 
-/* XXX: Remove me after getting rid of gail */
-extern void _gtk_accessibility_init (void);
-
 static void
 do_post_parse_initialization (int    *argc,
                               char ***argv)
@@ -711,9 +709,6 @@ do_post_parse_initialization (int    *argc,
 
   _gtk_register_resource ();
 
-  /* do what the call to gtk_type_init() used to do */
-  g_type_init ();
-
   _gtk_accel_map_init ();
 
   /* Set the 'initialized' flag.
@@ -1157,9 +1152,9 @@ gtk_main (void)
 
   if (g_main_loop_is_running (main_loops->data))
     {
-      GDK_THREADS_LEAVE ();
+      gdk_threads_leave ();
       g_main_loop_run (loop);
-      GDK_THREADS_ENTER ();
+      gdk_threads_enter ();
       gdk_flush ();
     }
 
@@ -1171,11 +1166,15 @@ gtk_main (void)
 
   if (gtk_main_loop_level == 0)
     {
+      /* Keep this section in sync with gtk_application_shutdown() */
+
       /* Try storing all clipboard data we have */
       _gtk_clipboard_store_all ();
 
       /* Synchronize the recent manager singleton */
       _gtk_recent_manager_sync ();
+
+      _gtk_accessibility_shutdown ();
     }
 }
 
@@ -1234,9 +1233,9 @@ gtk_events_pending (void)
 {
   gboolean result;
 
-  GDK_THREADS_LEAVE ();
+  gdk_threads_leave ();
   result = g_main_context_pending (NULL);
-  GDK_THREADS_ENTER ();
+  gdk_threads_enter ();
 
   return result;
 }
@@ -1257,9 +1256,9 @@ gtk_events_pending (void)
 gboolean
 gtk_main_iteration (void)
 {
-  GDK_THREADS_LEAVE ();
+  gdk_threads_leave ();
   g_main_context_iteration (NULL, TRUE);
-  GDK_THREADS_ENTER ();
+  gdk_threads_enter ();
 
   if (main_loops)
     return !g_main_loop_is_running (main_loops->data);
@@ -1281,9 +1280,9 @@ gtk_main_iteration (void)
 gboolean
 gtk_main_iteration_do (gboolean blocking)
 {
-  GDK_THREADS_LEAVE ();
+  gdk_threads_leave ();
   g_main_context_iteration (NULL, blocking);
-  GDK_THREADS_ENTER ();
+  gdk_threads_enter ();
 
   if (main_loops)
     return !g_main_loop_is_running (main_loops->data);
@@ -1339,6 +1338,14 @@ rewrite_event_for_window (GdkEvent  *event,
                                 new_window,
                                 &event->motion.x, &event->motion.y);
       break;
+    case GDK_TOUCH_BEGIN:
+    case GDK_TOUCH_UPDATE:
+    case GDK_TOUCH_END:
+    case GDK_TOUCH_CANCEL:
+      rewrite_events_translate (event->any.window,
+                                new_window,
+                                &event->touch.x, &event->touch.y);
+      break;
     case GDK_KEY_PRESS:
     case GDK_KEY_RELEASE:
     case GDK_PROXIMITY_IN:
@@ -1384,6 +1391,10 @@ rewrite_event_for_grabs (GdkEvent *event)
     case GDK_PROXIMITY_OUT:
     case GDK_KEY_PRESS:
     case GDK_KEY_RELEASE:
+    case GDK_TOUCH_BEGIN:
+    case GDK_TOUCH_UPDATE:
+    case GDK_TOUCH_END:
+    case GDK_TOUCH_CANCEL:
       display = gdk_window_get_display (event->any.window);
       device = gdk_event_get_device (event);
 
@@ -1428,8 +1439,7 @@ rewrite_event_for_grabs (GdkEvent *event)
  * </para></listitem>
  * <listitem><para>
  *   Find the widget which got the event. If the widget can't be determined
- *   the event is thrown away unless it belongs to a INCR transaction. In that
- *   case it is passed to gtk_selection_incr_event().
+ *   the event is thrown away unless it belongs to a INCR transaction.
  * </para></listitem>
  * <listitem><para>
  *   Then the event is pushed onto a stack so you can query the currently
@@ -1471,6 +1481,7 @@ gtk_main_do_event (GdkEvent *event)
 {
   GtkWidget *event_widget;
   GtkWidget *grab_widget = NULL;
+  GtkWidget *topmost_widget = NULL;
   GtkWindowGroup *window_group;
   GdkEvent *rewritten_event = NULL;
   GdkDevice *device;
@@ -1530,12 +1541,20 @@ gtk_main_do_event (GdkEvent *event)
   if (!grab_widget)
     grab_widget = gtk_window_group_get_current_grab (window_group);
 
+  /* Find out the topmost widget where captured event propagation
+   * should start, which is the widget holding the GTK+ grab
+   * if any, otherwise it's left NULL and events are emitted
+   * from the toplevel (or topmost parentless parent).
+   */
+  if (grab_widget)
+    topmost_widget = grab_widget;
+
   /* If the grab widget is an ancestor of the event widget
    * then we send the event to the original event widget.
    * This is the key to implementing modality.
    */
   if (!grab_widget ||
-      (gtk_widget_is_sensitive (event_widget) &&
+      ((gtk_widget_is_sensitive (event_widget) || event->type == GDK_SCROLL) &&
        gtk_widget_is_ancestor (event_widget, grab_widget)))
     grab_widget = event_widget;
 
@@ -1626,14 +1645,17 @@ gtk_main_do_event (GdkEvent *event)
     case GDK_WINDOW_STATE:
     case GDK_GRAB_BROKEN:
     case GDK_DAMAGE:
-      gtk_widget_event (event_widget, event);
+      if (!_gtk_widget_captured_event (event_widget, event))
+        gtk_widget_event (event_widget, event);
       break;
 
     case GDK_SCROLL:
     case GDK_BUTTON_PRESS:
     case GDK_2BUTTON_PRESS:
     case GDK_3BUTTON_PRESS:
-      gtk_propagate_event (grab_widget, event);
+    case GDK_TOUCH_BEGIN:
+      if (!_gtk_propagate_captured_event (grab_widget, event, topmost_widget))
+        gtk_propagate_event (grab_widget, event);
       break;
 
     case GDK_KEY_PRESS:
@@ -1674,7 +1696,12 @@ gtk_main_do_event (GdkEvent *event)
 
               window = gtk_widget_get_toplevel (grab_widget);
               if (GTK_IS_WINDOW (window))
-                gtk_window_set_mnemonics_visible (GTK_WINDOW (window), mnemonics_visible);
+                {
+                  if (mnemonics_visible)
+                    _gtk_window_set_auto_mnemonics_visible (GTK_WINDOW (window));
+                  else
+                    gtk_window_set_mnemonics_visible (GTK_WINDOW (window), FALSE);
+                }
             }
         }
       /* else fall through */
@@ -1682,7 +1709,11 @@ gtk_main_do_event (GdkEvent *event)
     case GDK_BUTTON_RELEASE:
     case GDK_PROXIMITY_IN:
     case GDK_PROXIMITY_OUT:
-      gtk_propagate_event (grab_widget, event);
+    case GDK_TOUCH_UPDATE:
+    case GDK_TOUCH_END:
+    case GDK_TOUCH_CANCEL:
+      if (!_gtk_propagate_captured_event (grab_widget, event, topmost_widget))
+        gtk_propagate_event (grab_widget, event);
       break;
 
     case GDK_ENTER_NOTIFY:
@@ -1691,7 +1722,8 @@ gtk_main_do_event (GdkEvent *event)
         _gtk_widget_set_device_window (event_widget,
                                        gdk_event_get_device (event),
                                        event->any.window);
-      if (gtk_widget_is_sensitive (grab_widget))
+      if (gtk_widget_is_sensitive (grab_widget) &&
+          !_gtk_propagate_captured_event (grab_widget, event, topmost_widget))
         gtk_widget_event (grab_widget, event);
       break;
 
@@ -1701,7 +1733,8 @@ gtk_main_do_event (GdkEvent *event)
         _gtk_widget_set_device_window (event_widget,
                                        gdk_event_get_device (event),
                                        NULL);
-      if (gtk_widget_is_sensitive (grab_widget))
+      if (gtk_widget_is_sensitive (grab_widget) &&
+          !_gtk_propagate_captured_event (grab_widget, event, topmost_widget))
         gtk_widget_event (grab_widget, event);
       break;
 
@@ -1729,6 +1762,7 @@ gtk_main_do_event (GdkEvent *event)
       || event->type == GDK_DRAG_ENTER
       || event->type == GDK_GRAB_BROKEN
       || event->type == GDK_MOTION_NOTIFY
+      || event->type == GDK_TOUCH_UPDATE
       || event->type == GDK_SCROLL)
     {
       _gtk_tooltip_handle_event (event);
@@ -2076,7 +2110,7 @@ gtk_grab_remove (GtkWidget *widget)
 /**
  * gtk_device_grab_add:
  * @widget: a #GtkWidget
- * @device: a #GtkDevice to grab on.
+ * @device: a #GdkDevice to grab on.
  * @block_others: %TRUE to prevent other devices to interact with @widget.
  *
  * Adds a GTK+ grab on @device, so all the events on @device and its
@@ -2206,7 +2240,7 @@ gtk_invoke_key_snoopers (GtkWidget *grab_widget,
   GSList *slist;
   gint return_val = FALSE;
 
-  return_val = _gail_util_key_snooper (grab_widget, (GdkEventKey *) event);
+  return_val = _gtk_accessibility_key_snooper (grab_widget, (GdkEventKey *) event);
 
   slist = key_snoopers;
   while (slist && !return_val)
@@ -2331,45 +2365,104 @@ gtk_get_event_widget (GdkEvent *event)
   return widget;
 }
 
-/**
- * gtk_propagate_event:
- * @widget: a #GtkWidget
- * @event: an event
- *
- * Sends an event to a widget, propagating the event to parent widgets
- * if the event remains unhandled.
- *
- * Events received by GTK+ from GDK normally begin in gtk_main_do_event().
- * Depending on the type of event, existence of modal dialogs, grabs, etc.,
- * the event may be propagated; if so, this function is used.
- *
- * gtk_propagate_event() calls gtk_widget_event() on each widget it
- * decides to send the event to. So gtk_widget_event() is the lowest-level
- * function; it simply emits the #GtkWidget::event and possibly an
- * event-specific signal on a widget. gtk_propagate_event() is a bit
- * higher-level, and gtk_main_do_event() is the highest level.
- *
- * All that said, you most likely don't want to use any of these
- * functions; synthesizing events is rarely needed. There are almost
- * certainly better ways to achieve your goals. For example, use
- * gdk_window_invalidate_rect() or gtk_widget_queue_draw() instead
- * of making up expose events.
- */
-void
-gtk_propagate_event (GtkWidget *widget,
-                     GdkEvent  *event)
+static gboolean
+propagate_event_up (GtkWidget *widget,
+                    GdkEvent  *event,
+                    GtkWidget *topmost)
 {
-  gint handled_event;
+  gboolean handled_event = FALSE;
 
-  g_return_if_fail (GTK_IS_WIDGET (widget));
-  g_return_if_fail (event != NULL);
+  /* Propagate event up the widget tree so that
+   * parents can see the button and motion
+   * events of the children.
+   */
+  while (TRUE)
+    {
+      GtkWidget *tmp;
+
+      g_object_ref (widget);
+
+      /* Scroll events are special cased here because it
+       * feels wrong when scrolling a GtkViewport, say,
+       * to have children of the viewport eat the scroll
+       * event
+       */
+      if (!gtk_widget_is_sensitive (widget))
+        handled_event = event->type != GDK_SCROLL;
+      else
+        handled_event = gtk_widget_event (widget, event);
+
+      tmp = gtk_widget_get_parent (widget);
+      g_object_unref (widget);
+
+      if (widget == topmost)
+        break;
+
+      widget = tmp;
+
+      if (handled_event || !widget)
+        break;
+    }
+
+  return handled_event;
+}
+
+static gboolean
+propagate_event_down (GtkWidget *widget,
+                      GdkEvent  *event,
+                      GtkWidget *topmost)
+{
+  gint handled_event = FALSE;
+  GList *widgets = NULL;
+  GList *l;
+
+  widgets = g_list_prepend (widgets, g_object_ref (widget));
+  while (widget && widget != topmost)
+    {
+      widget = gtk_widget_get_parent (widget);
+      if (!widget)
+        break;
 
-  handled_event = FALSE;
+      widgets = g_list_prepend (widgets, g_object_ref (widget));
 
-  g_object_ref (widget);
+      if (widget == topmost)
+        break;
+    }
 
-  if ((event->type == GDK_KEY_PRESS) ||
-      (event->type == GDK_KEY_RELEASE))
+  for (l = widgets; l && !handled_event; l = g_list_next (l))
+    {
+      widget = (GtkWidget *)l->data;
+
+      if (!gtk_widget_is_sensitive (widget))
+        {
+          /* stop propagating on SCROLL, but don't handle the event, so it
+           * can propagate up again and reach its handling widget
+           */
+          if (event->type == GDK_SCROLL)
+            break;
+          else
+            handled_event = TRUE;
+        }
+      else
+        handled_event = _gtk_widget_captured_event (widget, event);
+    }
+  g_list_free_full (widgets, (GDestroyNotify)g_object_unref);
+
+  return handled_event;
+}
+
+static gboolean
+propagate_event (GtkWidget *widget,
+                 GdkEvent  *event,
+                 gboolean   captured,
+                 GtkWidget *topmost)
+{
+  gboolean handled_event = FALSE;
+  gboolean (* propagate_func) (GtkWidget *widget, GdkEvent  *event);
+
+  propagate_func = captured ? _gtk_widget_captured_event : gtk_widget_event;
+
+  if (event->type == GDK_KEY_PRESS || event->type == GDK_KEY_RELEASE)
     {
       /* Only send key events within Window widgets to the Window
        * The Window widget will in turn pass the
@@ -2381,11 +2474,12 @@ gtk_propagate_event (GtkWidget *widget,
       window = gtk_widget_get_toplevel (widget);
       if (GTK_IS_WINDOW (window))
         {
+          g_object_ref (widget);
           /* If there is a grab within the window, give the grab widget
            * a first crack at the key event
            */
           if (widget != window && gtk_widget_has_grab (widget))
-            handled_event = gtk_widget_event (widget, event);
+            handled_event = propagate_func (widget, event);
 
           if (!handled_event)
             {
@@ -2393,45 +2487,59 @@ gtk_propagate_event (GtkWidget *widget,
               if (GTK_IS_WINDOW (window))
                 {
                   if (gtk_widget_is_sensitive (window))
-                    gtk_widget_event (window, event);
+                    handled_event = propagate_func (window, event);
                 }
             }
 
-          handled_event = TRUE; /* don't send to widget */
+          g_object_unref (widget);
+          return handled_event;
         }
     }
 
-  /* Other events get propagated up the widget tree
-   * so that parents can see the button and motion
-   * events of the children.
-   */
-  if (!handled_event)
-    {
-      while (TRUE)
-        {
-          GtkWidget *tmp;
-
-          /* Scroll events are special cased here because it
-           * feels wrong when scrolling a GtkViewport, say,
-           * to have children of the viewport eat the scroll
-           * event
-           */
-          if (!gtk_widget_is_sensitive (widget))
-            handled_event = event->type != GDK_SCROLL;
-          else
-            handled_event = gtk_widget_event (widget, event);
+  /* Other events get propagated up/down the widget tree */
+  return captured ?
+    propagate_event_down (widget, event, topmost) :
+    propagate_event_up (widget, event, topmost);
+}
 
-          tmp = gtk_widget_get_parent (widget);
-          g_object_unref (widget);
+/**
+ * gtk_propagate_event:
+ * @widget: a #GtkWidget
+ * @event: an event
+ *
+ * Sends an event to a widget, propagating the event to parent widgets
+ * if the event remains unhandled.
+ *
+ * Events received by GTK+ from GDK normally begin in gtk_main_do_event().
+ * Depending on the type of event, existence of modal dialogs, grabs, etc.,
+ * the event may be propagated; if so, this function is used.
+ *
+ * gtk_propagate_event() calls gtk_widget_event() on each widget it
+ * decides to send the event to. So gtk_widget_event() is the lowest-level
+ * function; it simply emits the #GtkWidget::event and possibly an
+ * event-specific signal on a widget. gtk_propagate_event() is a bit
+ * higher-level, and gtk_main_do_event() is the highest level.
+ *
+ * All that said, you most likely don't want to use any of these
+ * functions; synthesizing events is rarely needed. There are almost
+ * certainly better ways to achieve your goals. For example, use
+ * gdk_window_invalidate_rect() or gtk_widget_queue_draw() instead
+ * of making up expose events.
+ */
+void
+gtk_propagate_event (GtkWidget *widget,
+                     GdkEvent  *event)
+{
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+  g_return_if_fail (event != NULL);
 
-          widget = tmp;
+  propagate_event (widget, event, FALSE, NULL);
+}
 
-          if (!handled_event && widget)
-            g_object_ref (widget);
-          else
-            break;
-        }
-    }
-  else
-    g_object_unref (widget);
+gboolean
+_gtk_propagate_captured_event (GtkWidget *widget,
+                               GdkEvent  *event,
+                               GtkWidget *topmost)
+{
+  return propagate_event (widget, event, TRUE, topmost);
 }