diff --git a/gdk/quartz/gdkdevice-core-quartz.c b/gdk/quartz/gdkdevice-core-quartz.c
index 2f8781c..797a592 100644
--- a/gdk/quartz/gdkdevice-core-quartz.c
+++ b/gdk/quartz/gdkdevice-core-quartz.c
@@ -241,9 +241,7 @@ gdk_quartz_device_core_query_state_helper (GdkWindow       *window,
   found_window = _gdk_quartz_window_find_child (window, x_tmp, y_tmp,
                                                 FALSE);
 
-  if (found_window == _gdk_root)
-    found_window = NULL;
-  else if (found_window)
+  if (found_window && found_window != _gdk_root)
     translate_coords_to_child_coords (window, found_window,
                                       &x_tmp, &y_tmp);
 
@@ -272,6 +270,9 @@ gdk_quartz_device_core_query_state (GdkDevice        *device,
   NSPoint point;
   gint x_tmp, y_tmp;
 
+  if (root_window)
+    *root_window = _gdk_root;
+
   found_window = gdk_quartz_device_core_query_state_helper (window, device,
                                                             win_x, win_y,
                                                             mask);
@@ -280,9 +281,6 @@ gdk_quartz_device_core_query_state (GdkDevice        *device,
 
   display = gdk_window_get_display (window);
 
-  if (root_window)
-    *root_window = _gdk_root;
-
   if (child_window)
     *child_window = found_window;
 
@@ -298,6 +296,7 @@ gdk_quartz_device_core_query_state (GdkDevice        *device,
   return TRUE;
 }
 
+
 static GdkGrabStatus
 gdk_quartz_device_core_grab (GdkDevice    *device,
                              GdkWindow    *window,
@@ -307,7 +306,9 @@ gdk_quartz_device_core_grab (GdkDevice    *device,
                              GdkCursor    *cursor,
                              guint32       time_)
 {
-  /* Should remain empty */
+  if (device->source == GDK_SOURCE_MOUSE)
+    _gdk_quartz_display_add_pointer_grab (device->display);
+
   return GDK_GRAB_SUCCESS;
 }
 
@@ -321,6 +322,9 @@ gdk_quartz_device_core_ungrab (GdkDevice *device,
   if (grab)
     grab->serial_end = 0;
 
+  if (device->source == GDK_SOURCE_MOUSE)
+    _gdk_quartz_display_remove_pointer_grab (device->display);
+
   _gdk_display_device_grab_update (_gdk_display, device, NULL, 0);
 }
 
diff --git a/gdk/quartz/gdkdisplay-quartz.c b/gdk/quartz/gdkdisplay-quartz.c
index 4773932..53b8f50 100644
--- a/gdk/quartz/gdkdisplay-quartz.c
+++ b/gdk/quartz/gdkdisplay-quartz.c
@@ -35,6 +35,10 @@ struct _GdkQuartzDisplay
   GdkDisplay display;
 
   GList *input_devices;
+
+  gboolean event_tap_installed;
+  CFMachPortRef event_tap;
+  CFRunLoopSourceRef run_loop_source;
 };
 
 struct _GdkQuartzDisplayClass
@@ -142,6 +146,90 @@ _gdk_quartz_display_open (const gchar *display_name)
   return _gdk_display;
 }
 
+static CGEventRef
+pointer_grab_global_event_callback (CGEventTapProxy proxy,
+                                    CGEventType type,
+                                    CGEventRef event,
+                                    void *refcon)
+{
+  NSEvent *nsevent;
+
+  if (type != kCGEventLeftMouseDown &&
+      type != kCGEventRightMouseDown &&
+      type != kCGEventOtherMouseDown)
+    return event;
+
+  GDK_QUARTZ_ALLOC_POOL;
+
+  nsevent = [NSEvent eventWithCGEvent:event];
+  _gdk_quartz_events_handle_global_mouse_down (nsevent);
+
+  GDK_QUARTZ_RELEASE_POOL;
+
+  return event;
+}
+
+void
+_gdk_quartz_display_add_pointer_grab (GdkDisplay *display)
+{
+  GdkQuartzDisplay *display_quartz = GDK_QUARTZ_DISPLAY (display);
+
+  if (!display_quartz->event_tap_installed)
+    {
+      if (!display_quartz->event_tap)
+        {
+          CGEventMask event_mask;
+
+          event_mask = CGEventMaskBit (kCGEventLeftMouseDown) |
+              CGEventMaskBit (kCGEventRightMouseDown) |
+              CGEventMaskBit (kCGEventOtherMouseDown);
+
+          display_quartz->event_tap = CGEventTapCreate (kCGHIDEventTap,
+                                                        kCGHeadInsertEventTap,
+                                                        kCGEventTapOptionListenOnly,
+                                                        event_mask,
+                                                        pointer_grab_global_event_callback,
+                                                        NULL);
+
+          display_quartz->run_loop_source =
+              CFMachPortCreateRunLoopSource (kCFAllocatorDefault,
+                                             display_quartz->event_tap, 0);
+        }
+
+      if (display_quartz->event_tap)
+        {
+          /* FIXME: Can we rely on CFRunLoopGetCurrent() to always get
+           * us the right run loop?
+           */
+          CFRunLoopAddSource (CFRunLoopGetCurrent (),
+                              display_quartz->run_loop_source,
+                              kCFRunLoopCommonModes);
+          CGEventTapEnable (display_quartz->event_tap, YES);
+        }
+
+      display_quartz->event_tap_installed = TRUE;
+    }
+}
+
+void
+_gdk_quartz_display_remove_pointer_grab (GdkDisplay *display)
+{
+  GdkQuartzDisplay *display_quartz = GDK_QUARTZ_DISPLAY (display);
+
+  if (display_quartz->event_tap_installed)
+    {
+      /* FIXME: Can we rely on CFRunLoopGetCurrent() to always get
+       * us the right run loop?
+       */
+      CFRunLoopRemoveSource (CFRunLoopGetCurrent (),
+                             display_quartz->run_loop_source,
+                             kCFRunLoopCommonModes);
+      CGEventTapEnable (display_quartz->event_tap, NO);
+
+      display_quartz->event_tap_installed = FALSE;
+    }
+}
+
 static const gchar *
 gdk_quartz_display_get_name (GdkDisplay *display)
 {
diff --git a/gdk/quartz/gdkevents-quartz.c b/gdk/quartz/gdkevents-quartz.c
index c611c0a..f71c7c2 100644
--- a/gdk/quartz/gdkevents-quartz.c
+++ b/gdk/quartz/gdkevents-quartz.c
@@ -748,6 +748,27 @@ find_window_for_ns_event (NSEvent *nsevent,
   return NULL;
 }
 
+/* We assume the events received are mouse down events through an
+ * event tap.  These get special treatment and we only use them
+ * to see if we need to break grabs.
+ */
+void
+_gdk_quartz_events_handle_global_mouse_down (NSEvent *nsevent)
+{
+  int x, y;
+  NSPoint screen_point;
+  GdkWindow *window;
+
+  screen_point = [nsevent locationInWindow];
+  window = find_toplevel_under_pointer (_gdk_display, screen_point, &x, &y);
+
+  /* If we could not find a toplevel window, then this event is
+   * outside of the application.  In this case, break the grabs.
+   */
+  if (!window)
+    break_all_grabs (get_time_from_ns_event (nsevent));
+}
+
 static void
 fill_crossing_event (GdkWindow       *toplevel,
                      GdkEvent        *event,
diff --git a/gdk/quartz/gdkprivate-quartz.h b/gdk/quartz/gdkprivate-quartz.h
index 6a05e25..5b6eeb4 100644
--- a/gdk/quartz/gdkprivate-quartz.h
+++ b/gdk/quartz/gdkprivate-quartz.h
@@ -65,6 +65,7 @@ void         _gdk_quartz_events_send_map_event         (GdkWindow *window);
 GdkEventMask _gdk_quartz_events_get_current_event_mask (void);
 
 void         _gdk_quartz_events_send_enter_notify_event (GdkWindow *window);
+void         _gdk_quartz_events_handle_global_mouse_down (NSEvent *event);
 
 /* Event loop */
 gboolean   _gdk_quartz_event_loop_check_pending (void);
@@ -85,6 +86,9 @@ GdkDragContext * _gdk_quartz_window_drag_begin   (GdkWindow   *window,
 
 GdkDisplay *    _gdk_quartz_display_open (const gchar *name);
 
+void _gdk_quartz_display_add_pointer_grab (GdkDisplay *display);
+void _gdk_quartz_display_remove_pointer_grab (GdkDisplay *display);
+
 /* Display methods - events */
 void     _gdk_quartz_display_queue_events (GdkDisplay *display);
 gboolean _gdk_quartz_display_has_pending  (GdkDisplay *display);
