]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkmain.c
Add GtkBubbleWindow
[~andy/gtk] / gtk / gtkmain.c
index 67d843e433fb360b4fbc329ceae93ac19ea932de..f5b4c5a520fcab8e9317930f1a416597990c8b45 100644 (file)
@@ -12,9 +12,7 @@
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  */
 
 /*
 #include "gtkmodulesprivate.h"
 #include "gtkprivate.h"
 #include "gtkrecentmanager.h"
+#include "gtkresources.h"
 #include "gtkselectionprivate.h"
 #include "gtksettingsprivate.h"
 #include "gtktooltip.h"
 #include "gtkwidgetprivate.h"
 #include "gtkwindowprivate.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)
@@ -709,8 +707,7 @@ do_post_parse_initialization (int    *argc,
       g_warning ("Whoever translated default:LTR did so wrongly.\n");
   }
 
-  /* do what the call to gtk_type_init() used to do */
-  g_type_init ();
+  _gtk_register_resource ();
 
   _gtk_accel_map_init ();
 
@@ -1155,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 ();
     }
 
@@ -1169,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 ();
     }
 }
 
@@ -1232,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;
 }
@@ -1255,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);
@@ -1279,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);
@@ -1337,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:
@@ -1382,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);
 
@@ -1426,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
@@ -1469,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;
@@ -1528,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;
 
@@ -1624,23 +1645,23 @@ 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:
     case GDK_KEY_RELEASE:
-      if (key_snoopers)
-        {
-          if (gtk_invoke_key_snoopers (grab_widget, event))
-            break;
-        }
+      if (gtk_invoke_key_snoopers (grab_widget, event))
+        break;
 
       /* make focus visible in a window that receives a key event */
       {
@@ -1675,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 */
@@ -1683,22 +1709,32 @@ 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:
-      _gtk_widget_set_device_window (event_widget,
-                                     gdk_event_get_device (event),
-                                     event->any.window);
-      if (gtk_widget_is_sensitive (grab_widget))
+      if (event->crossing.detail != GDK_NOTIFY_VIRTUAL &&
+          event->crossing.detail != GDK_NOTIFY_NONLINEAR_VIRTUAL)
+        _gtk_widget_set_device_window (event_widget,
+                                       gdk_event_get_device (event),
+                                       event->any.window);
+      if (gtk_widget_is_sensitive (grab_widget) &&
+          !_gtk_propagate_captured_event (grab_widget, event, topmost_widget))
         gtk_widget_event (grab_widget, event);
       break;
 
     case GDK_LEAVE_NOTIFY:
-      _gtk_widget_set_device_window (event_widget,
-                                     gdk_event_get_device (event),
-                                     NULL);
-      if (gtk_widget_is_sensitive (grab_widget))
+      if (event->crossing.detail != GDK_NOTIFY_VIRTUAL &&
+          event->crossing.detail != GDK_NOTIFY_NONLINEAR_VIRTUAL)
+        _gtk_widget_set_device_window (event_widget,
+                                       gdk_event_get_device (event),
+                                       NULL);
+      if (gtk_widget_is_sensitive (grab_widget) &&
+          !_gtk_propagate_captured_event (grab_widget, event, topmost_widget))
         gtk_widget_event (grab_widget, event);
       break;
 
@@ -1726,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);
@@ -2073,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
@@ -2142,6 +2179,9 @@ gtk_device_grab_remove (GtkWidget *widget,
  *
  * Returns: a unique id for this key snooper for use with
  *    gtk_key_snooper_remove().
+ *
+ * Deprecated: 3.4: Key snooping should not be done. Events should
+ *     be handled by widgets.
  */
 guint
 gtk_key_snooper_install (GtkKeySnoopFunc snooper,
@@ -2166,6 +2206,9 @@ gtk_key_snooper_install (GtkKeySnoopFunc snooper,
  * @snooper_handler_id: Identifies the key snooper to remove
  *
  * Removes the key snooper function with the given id.
+ *
+ * Deprecated: 3.4: Key snooping should not be done. Events should
+ *     be handled by widgets.
  */
 void
 gtk_key_snooper_remove (guint snooper_id)
@@ -2197,6 +2240,8 @@ gtk_invoke_key_snoopers (GtkWidget *grab_widget,
   GSList *slist;
   gint return_val = FALSE;
 
+  return_val = _gtk_accessibility_key_snooper (grab_widget, (GdkEventKey *) event);
+
   slist = key_snoopers;
   while (slist && !return_val)
     {
@@ -2320,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);
 
-  handled_event = FALSE;
+      /* 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);
 
-  g_object_ref (widget);
+      tmp = gtk_widget_get_parent (widget);
+      g_object_unref (widget);
+
+      if (widget == topmost)
+        break;
+
+      widget = tmp;
+
+      if (handled_event || !widget)
+        break;
+    }
 
-  if ((event->type == GDK_KEY_PRESS) ||
-      (event->type == GDK_KEY_RELEASE))
+  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;
+
+      widgets = g_list_prepend (widgets, g_object_ref (widget));
+
+      if (widget == topmost)
+        break;
+    }
+
+  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
@@ -2370,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)
             {
@@ -2382,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);
 }