]> Pileus Git - ~andy/gtk/blobdiff - gdk/quartz/gdkevents-quartz.c
GtkImageAccessible: add a private struct
[~andy/gtk] / gdk / quartz / gdkevents-quartz.c
index 44f10cbbf407fb2409b83823e2a773e37e6753e9..712f23245a88e22f6f23fb23e1c7f581ab92742a 100644 (file)
@@ -15,9 +15,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 "config.h"
 #import <Cocoa/Cocoa.h>
 #include <Carbon/Carbon.h>
 
+#include <gdk/gdkdisplayprivate.h>
+
 #include "gdkscreen.h"
 #include "gdkkeysyms.h"
+#include "gdkquartz.h"
+#include "gdkquartzdisplay.h"
 #include "gdkprivate-quartz.h"
-#include "gdkdevicemanager-core.h"
+#include "gdkquartzdevicemanager-core.h"
 
 #define GRIP_WIDTH 15
 #define GRIP_HEIGHT 15
+#define GDK_LION_RESIZE 5
 
 #define WINDOW_IS_TOPLEVEL(window)                  \
   (GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD &&   \
 /* This is the window corresponding to the key window */
 static GdkWindow   *current_keyboard_window;
 
-/* This is the event mask and button state from the last event */
-static GdkEventMask current_event_mask;
-static int          current_button_state;
 
 static void append_event                        (GdkEvent  *event,
                                                  gboolean   windowing);
 
-NSEvent *
-gdk_quartz_event_get_nsevent (GdkEvent *event)
-{
-  /* FIXME: If the event here is unallocated, we crash. */
-  return ((GdkEventPrivate *) event)->windowing_data;
-}
+static GdkWindow *find_toplevel_under_pointer   (GdkDisplay *display,
+                                                 NSPoint     screen_point,
+                                                 gint       *x,
+                                                 gint       *y);
 
-void
-_gdk_events_init (void)
+
+static void
+gdk_quartz_ns_notification_callback (CFNotificationCenterRef  center,
+                                     void                    *observer,
+                                     CFStringRef              name,
+                                     const void              *object,
+                                     CFDictionaryRef          userInfo)
 {
-  _gdk_quartz_event_loop_init ();
+  GdkEvent new_event;
 
-  current_keyboard_window = g_object_ref (_gdk_root);
+  new_event.type = GDK_SETTING;
+  new_event.setting.window = gdk_screen_get_root_window (_gdk_screen);
+  new_event.setting.send_event = FALSE;
+  new_event.setting.action = GDK_SETTING_ACTION_CHANGED;
+  new_event.setting.name = NULL;
+
+  /* Translate name */
+  if (CFStringCompare (name,
+                       CFSTR("AppleNoRedisplayAppearancePreferenceChanged"),
+                       0) == kCFCompareEqualTo)
+    new_event.setting.name = "gtk-primary-button-warps-slider";
+
+  if (!new_event.setting.name)
+    return;
+
+  gdk_event_put (&new_event);
 }
 
-gboolean
-gdk_events_pending (void)
+static void
+gdk_quartz_events_init_notifications (void)
 {
-  return (_gdk_event_queue_find_first (_gdk_display) ||
-         (_gdk_quartz_event_loop_check_pending ()));
+  static gboolean notifications_initialized = FALSE;
+
+  if (notifications_initialized)
+    return;
+  notifications_initialized = TRUE;
+
+  /* Initialize any handlers for notifications we want to push to GTK
+   * through GdkEventSettings.
+   */
+
+  /* This is an undocumented *distributed* notification to listen for changes
+   * in scrollbar jump behavior. It is used by LibreOffice and WebKit as well.
+   */
+  CFNotificationCenterAddObserver (CFNotificationCenterGetDistributedCenter (),
+                                   NULL,
+                                   &gdk_quartz_ns_notification_callback,
+                                   CFSTR ("AppleNoRedisplayAppearancePreferenceChanged"),
+                                   NULL,
+                                   CFNotificationSuspensionBehaviorDeliverImmediately);
 }
 
 void
-gdk_device_ungrab (GdkDevice *device,
-                   guint32    time_)
+_gdk_quartz_events_init (void)
 {
-  GdkDeviceGrabInfo *grab;
-
-  grab = _gdk_display_get_last_device_grab (_gdk_display, device);
-  if (grab)
-    grab->serial_end = 0;
+  _gdk_quartz_event_loop_init ();
+  gdk_quartz_events_init_notifications ();
 
-  _gdk_display_device_grab_update (_gdk_display, device, 0);
+  current_keyboard_window = g_object_ref (_gdk_root);
 }
 
-GdkGrabStatus
-_gdk_windowing_device_grab (GdkDevice    *device,
-                            GdkWindow    *window,
-                            GdkWindow    *native,
-                            gboolean      owner_events,
-                            GdkEventMask  event_mask,
-                            GdkWindow    *confine_to,
-                            GdkCursor    *cursor,
-                            guint32       time)
+gboolean
+_gdk_quartz_display_has_pending (GdkDisplay *display)
 {
-  g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
-  g_return_val_if_fail (confine_to == NULL || GDK_IS_WINDOW (confine_to), 0);
-
-  if (!window || GDK_WINDOW_DESTROYED (window))
-    return GDK_GRAB_NOT_VIEWABLE;
-
-  _gdk_display_add_device_grab (_gdk_display,
-                                device,
-                                window,
-                                native,
-                                GDK_OWNERSHIP_NONE,
-                                owner_events,
-                                event_mask,
-                                0,
-                                time,
-                                FALSE);
-
-  return GDK_GRAB_SUCCESS;
+  return (_gdk_event_queue_find_first (display) ||
+         (_gdk_quartz_event_loop_check_pending ()));
 }
 
-static void
-break_all_grabs (guint32 time)
+void
+_gdk_quartz_events_break_all_grabs (guint32 time)
 {
   GList *list, *l;
   GdkDeviceManager *device_manager;
@@ -137,7 +145,7 @@ break_all_grabs (guint32 time)
           grab->implicit_ungrab = TRUE;
         }
 
-      _gdk_display_device_grab_update (_gdk_display, l->data, 0);
+      _gdk_display_device_grab_update (_gdk_display, l->data, NULL, 0);
     }
 
   g_list_free (list);
@@ -216,8 +224,11 @@ static guint32
 get_time_from_ns_event (NSEvent *event)
 {
   double time = [event timestamp];
-  
-  return time * 1000.0;
+
+  /* cast via double->uint64 conversion to make sure that it is
+   * wrapped on 32-bit machines when it overflows
+   */
+  return (guint32) (guint64) (time * 1000.0);
 }
 
 static int
@@ -240,6 +251,25 @@ get_mouse_button_from_ns_event (NSEvent *event)
     }
 }
 
+static GdkModifierType
+get_mouse_button_modifiers_from_ns_buttons (NSUInteger nsbuttons)
+{
+  GdkModifierType modifiers = 0;
+
+  if (nsbuttons & (1 << 0))
+    modifiers |= GDK_BUTTON1_MASK;
+  if (nsbuttons & (1 << 1))
+    modifiers |= GDK_BUTTON3_MASK;
+  if (nsbuttons & (1 << 2))
+    modifiers |= GDK_BUTTON2_MASK;
+  if (nsbuttons & (1 << 3))
+    modifiers |= GDK_BUTTON4_MASK;
+  if (nsbuttons & (1 << 4))
+    modifiers |= GDK_BUTTON5_MASK;
+
+  return modifiers;
+}
+
 static GdkModifierType
 get_mouse_button_modifiers_from_ns_event (NSEvent *event)
 {
@@ -255,25 +285,30 @@ get_mouse_button_modifiers_from_ns_event (NSEvent *event)
 }
 
 static GdkModifierType
-get_keyboard_modifiers_from_ns_event (NSEvent *nsevent)
+get_keyboard_modifiers_from_ns_flags (NSUInteger nsflags)
 {
   GdkModifierType modifiers = 0;
-  int nsflags;
 
-  nsflags = [nsevent modifierFlags];
-  
   if (nsflags & NSAlphaShiftKeyMask)
     modifiers |= GDK_LOCK_MASK;
   if (nsflags & NSShiftKeyMask)
     modifiers |= GDK_SHIFT_MASK;
   if (nsflags & NSControlKeyMask)
     modifiers |= GDK_CONTROL_MASK;
-  if (nsflags & NSCommandKeyMask)
+  if (nsflags & NSAlternateKeyMask)
     modifiers |= GDK_MOD1_MASK;
+  if (nsflags & NSCommandKeyMask)
+    modifiers |= GDK_MOD2_MASK;
 
   return modifiers;
 }
 
+static GdkModifierType
+get_keyboard_modifiers_from_ns_event (NSEvent *nsevent)
+{
+  return get_keyboard_modifiers_from_ns_flags ([nsevent modifierFlags]);
+}
+
 /* Return an event mask from an NSEvent */
 static GdkEventMask
 get_event_mask_from_ns_event (NSEvent *nsevent)
@@ -349,18 +384,73 @@ get_event_mask_from_ns_event (NSEvent *nsevent)
   return 0;
 }
 
+static void
+get_window_point_from_screen_point (GdkWindow *window,
+                                    NSPoint    screen_point,
+                                    gint      *x,
+                                    gint      *y)
+{
+  NSPoint point;
+  NSWindow *nswindow;
+
+  nswindow = ((GdkWindowImplQuartz *)window->impl)->toplevel;
+
+  point = [nswindow convertScreenToBase:screen_point];
+
+  *x = point.x;
+  *y = window->height - point.y;
+}
+
+static GdkWindow *
+get_toplevel_from_ns_event (NSEvent *nsevent,
+                            NSPoint *screen_point,
+                            gint    *x,
+                            gint    *y)
+{
+  GdkWindow *toplevel;
+
+  if ([nsevent window])
+    {
+      GdkQuartzView *view;
+      NSPoint point;
+
+      view = (GdkQuartzView *)[[nsevent window] contentView];
+
+      toplevel = [view gdkWindow];
+
+      point = [nsevent locationInWindow];
+      *screen_point = [[nsevent window] convertBaseToScreen:point];
+
+      *x = point.x;
+      *y = toplevel->height - point.y;
+    }
+  else
+    {
+      /* Fallback used when no NSWindow set.  This happens e.g. when
+       * we allow motion events without a window set in gdk_event_translate()
+       * that occur immediately after the main menu bar was clicked/used.
+       */
+      *screen_point = [NSEvent mouseLocation];
+      toplevel = find_toplevel_under_pointer (_gdk_display,
+                                              *screen_point,
+                                              x, y);
+    }
+
+  return toplevel;
+}
+
 static GdkEvent *
 create_focus_event (GdkWindow *window,
                    gboolean   in)
 {
   GdkEvent *event;
-  GdkDeviceManagerCore *device_manager;
+  GdkQuartzDeviceManagerCore *device_manager;
 
   event = gdk_event_new (GDK_FOCUS_CHANGE);
   event->focus_change.window = window;
   event->focus_change.in = in;
 
-  device_manager = GDK_DEVICE_MANAGER_CORE (_gdk_display->device_manager);
+  device_manager = GDK_QUARTZ_DEVICE_MANAGER_CORE (_gdk_display->device_manager);
   gdk_event_set_device (event, device_manager->core_keyboard);
 
   return event;
@@ -370,33 +460,18 @@ create_focus_event (GdkWindow *window,
 static void
 generate_motion_event (GdkWindow *window)
 {
-  NSPoint point;
   NSPoint screen_point;
-  NSWindow *nswindow;
-  GdkQuartzView *view;
-  GdkWindowObject *private;
   GdkEvent *event;
   gint x, y, x_root, y_root;
-  GdkDisplay *display;
 
   event = gdk_event_new (GDK_MOTION_NOTIFY);
   event->any.window = NULL;
   event->any.send_event = TRUE;
 
-  private = (GdkWindowObject *)window;
-  nswindow = ((GdkWindowImplQuartz *)private->impl)->toplevel;
-  view = (GdkQuartzView *)[nswindow contentView];
-
-  display = gdk_window_get_display (window);
-
   screen_point = [NSEvent mouseLocation];
 
   _gdk_quartz_window_nspoint_to_gdk_xy (screen_point, &x_root, &y_root);
-
-  point = [nswindow convertScreenToBase:screen_point];
-
-  x = point.x;
-  y = private->height - point.y;
+  get_window_point_from_screen_point (window, screen_point, &x, &y);
 
   event->any.type = GDK_MOTION_NOTIFY;
   event->motion.window = window;
@@ -406,7 +481,8 @@ generate_motion_event (GdkWindow *window)
   event->motion.x_root = x_root;
   event->motion.y_root = y_root;
   /* FIXME event->axes */
-  event->motion.state = 0;
+  event->motion.state = _gdk_quartz_events_get_current_keyboard_modifiers () |
+                        _gdk_quartz_events_get_current_mouse_modifiers ();
   event->motion.is_hint = FALSE;
   event->motion.device = _gdk_display->core_pointer;
 
@@ -423,7 +499,7 @@ _gdk_quartz_events_update_focus_window (GdkWindow *window,
   if (got_focus && window == current_keyboard_window)
     return;
 
-  /* FIXME: Don't do this when grabbed? Or make GdkQuartzWindow
+  /* FIXME: Don't do this when grabbed? Or make GdkQuartzNSWindow
    * disallow it in the first place instead?
    */
   
@@ -461,10 +537,7 @@ _gdk_quartz_events_update_focus_window (GdkWindow *window,
 void
 _gdk_quartz_events_send_enter_notify_event (GdkWindow *window)
 {
-  NSPoint point;
   NSPoint screen_point;
-  NSWindow *nswindow;
-  GdkWindowObject *private;
   GdkEvent *event;
   gint x, y, x_root, y_root;
 
@@ -472,17 +545,10 @@ _gdk_quartz_events_send_enter_notify_event (GdkWindow *window)
   event->any.window = NULL;
   event->any.send_event = FALSE;
 
-  private = (GdkWindowObject *)window;
-  nswindow = ((GdkWindowImplQuartz *)private->impl)->toplevel;
-
   screen_point = [NSEvent mouseLocation];
 
   _gdk_quartz_window_nspoint_to_gdk_xy (screen_point, &x_root, &y_root);
-
-  point = [nswindow convertScreenToBase:screen_point];
-
-  x = point.x;
-  y = private->height - point.y;
+  get_window_point_from_screen_point (window, screen_point, &x, &y);
 
   event->crossing.window = window;
   event->crossing.subwindow = NULL;
@@ -493,7 +559,8 @@ _gdk_quartz_events_send_enter_notify_event (GdkWindow *window)
   event->crossing.y_root = y_root;
   event->crossing.mode = GDK_CROSSING_NORMAL;
   event->crossing.detail = GDK_NOTIFY_ANCESTOR;
-  event->crossing.state = 0;
+  event->crossing.state = _gdk_quartz_events_get_current_keyboard_modifiers () |
+                          _gdk_quartz_events_get_current_mouse_modifiers ();
 
   gdk_event_set_device (event, _gdk_display->core_pointer);
 
@@ -503,13 +570,12 @@ _gdk_quartz_events_send_enter_notify_event (GdkWindow *window)
 void
 _gdk_quartz_events_send_map_event (GdkWindow *window)
 {
-  GdkWindowObject *private = (GdkWindowObject *)window;
-  GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);
+  GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
 
   if (!impl->toplevel)
     return;
 
-  if (private->event_mask & GDK_STRUCTURE_MASK)
+  if (window->event_mask & GDK_STRUCTURE_MASK)
     {
       GdkEvent event;
 
@@ -532,19 +598,7 @@ find_toplevel_under_pointer (GdkDisplay *display,
   info = _gdk_display_get_pointer_info (display, display->core_pointer);
   toplevel = info->toplevel_under_pointer;
   if (toplevel && WINDOW_IS_TOPLEVEL (toplevel))
-    {
-      GdkWindowObject *private;
-      NSWindow *nswindow;
-      NSPoint point;
-
-      private = (GdkWindowObject *)toplevel;
-      nswindow = ((GdkWindowImplQuartz *)private->impl)->toplevel;
-
-      point = [nswindow convertScreenToBase:screen_point];
-
-      *x = point.x;
-      *y = private->height - point.y;
-    }
+    get_window_point_from_screen_point (toplevel, screen_point, x, y);
 
   return toplevel;
 }
@@ -592,24 +646,17 @@ find_toplevel_for_mouse_event (NSEvent    *nsevent,
                                gint       *x,
                                gint       *y)
 {
-  NSPoint point;
   NSPoint screen_point;
   NSEventType event_type;
   GdkWindow *toplevel;
-  GdkQuartzView *view;
   GdkDisplay *display;
   GdkDeviceGrabInfo *grab;
-  GdkWindowObject *private;
 
-  view = (GdkQuartzView *)[[nsevent window] contentView];
-  toplevel = [view gdkWindow];
+  toplevel = get_toplevel_from_ns_event (nsevent, &screen_point, x, y);
 
   display = gdk_window_get_display (toplevel);
-  private = GDK_WINDOW_OBJECT (toplevel);
 
   event_type = [nsevent type];
-  point = [nsevent locationInWindow];
-  screen_point = [[nsevent window] convertBaseToScreen:point];
 
   /* From the docs for XGrabPointer:
    *
@@ -657,18 +704,10 @@ find_toplevel_for_mouse_event (NSEvent    *nsevent,
         {
           /* Finally check the grab window. */
           GdkWindow *grab_toplevel;
-          GdkWindowObject *grab_private;
-          NSWindow *grab_nswindow;
 
           grab_toplevel = gdk_window_get_effective_toplevel (grab->window);
-          grab_private = (GdkWindowObject *)grab_toplevel;
-
-          grab_nswindow = ((GdkWindowImplQuartz *)grab_private->impl)->toplevel;
-          point = [grab_nswindow convertScreenToBase:screen_point];
-
-          /* Note: x_root and y_root are already right. */
-          *x = point.x;
-          *y = grab_private->height - point.y;
+          get_window_point_from_screen_point (grab_toplevel, screen_point,
+                                              x, y);
 
           return grab_toplevel;
         }
@@ -699,37 +738,11 @@ find_toplevel_for_mouse_event (NSEvent    *nsevent,
       if (toplevel_under_pointer
           && WINDOW_IS_TOPLEVEL (toplevel_under_pointer))
         {
-          GdkWindowObject *toplevel_private;
           GdkWindowImplQuartz *toplevel_impl;
 
           toplevel = toplevel_under_pointer;
 
-          toplevel_private = (GdkWindowObject *)toplevel;
-          toplevel_impl = (GdkWindowImplQuartz *)toplevel_private->impl;
-
-          if ([toplevel_impl->toplevel showsResizeIndicator])
-            {
-              NSRect frame;
-
-              /* If the resize indicator is visible and the event
-               * is in the lower right 15x15 corner, we leave these
-               * events to Cocoa as to be handled as resize events.
-               * Applications may have widgets in this area.  These
-               * will most likely be larger than 15x15 and for
-               * scroll bars there are also other means to move
-               * the scroll bar.  Since the resize indicator is
-               * the only way of resizing windows on Mac OS, it
-               * is too important to not make functional.
-               */
-              frame = [toplevel_impl->view bounds];
-              if (x_tmp > frame.size.width - GRIP_WIDTH
-                  && x_tmp < frame.size.width
-                  && y_tmp > frame.size.height - GRIP_HEIGHT
-                  && y_tmp < frame.size.height)
-                {
-                  return NULL;
-                }
-            }
+          toplevel_impl = (GdkWindowImplQuartz *)toplevel->impl;
 
           *x = x_tmp;
           *y = y_tmp;
@@ -752,22 +765,13 @@ find_window_for_ns_event (NSEvent *nsevent,
                           gint    *y_root)
 {
   GdkQuartzView *view;
-  NSPoint point;
+  GdkWindow *toplevel;
   NSPoint screen_point;
   NSEventType event_type;
-  GdkWindow *toplevel;
-  GdkWindowObject *private;
 
   view = (GdkQuartzView *)[[nsevent window] contentView];
-  toplevel = [view gdkWindow];
-  private = GDK_WINDOW_OBJECT (toplevel);
-
-  point = [nsevent locationInWindow];
-  screen_point = [[nsevent window] convertBaseToScreen:point];
-
-  *x = point.x;
-  *y = private->height - point.y;
 
+  toplevel = get_toplevel_from_ns_event (nsevent, &screen_point, x, y);
   _gdk_quartz_window_nspoint_to_gdk_xy (screen_point, x_root, y_root);
 
   event_type = [nsevent type];
@@ -832,7 +836,8 @@ fill_crossing_event (GdkWindow       *toplevel,
   event->crossing.y_root = y_root;
   event->crossing.mode = mode;
   event->crossing.detail = detail;
-  event->crossing.state = get_keyboard_modifiers_from_ns_event (nsevent);
+  event->crossing.state = get_keyboard_modifiers_from_ns_event (nsevent) |
+                         _gdk_quartz_events_get_current_mouse_modifiers ();
 
   gdk_event_set_device (event, _gdk_display->core_pointer);
 
@@ -850,9 +855,9 @@ fill_button_event (GdkWindow *window,
 {
   GdkEventType type;
   gint state;
-  gint button;
 
-  state = get_keyboard_modifiers_from_ns_event (nsevent);
+  state = get_keyboard_modifiers_from_ns_event (nsevent) |
+         _gdk_quartz_events_get_current_mouse_modifiers ();
 
   switch ([nsevent type])
     {
@@ -860,18 +865,19 @@ fill_button_event (GdkWindow *window,
     case NSRightMouseDown:
     case NSOtherMouseDown:
       type = GDK_BUTTON_PRESS;
+      state &= ~get_mouse_button_modifiers_from_ns_event (nsevent);
       break;
+
     case NSLeftMouseUp:
     case NSRightMouseUp:
     case NSOtherMouseUp:
       type = GDK_BUTTON_RELEASE;
       state |= get_mouse_button_modifiers_from_ns_event (nsevent);
       break;
+
     default:
       g_assert_not_reached ();
     }
-  
-  button = get_mouse_button_from_ns_event (nsevent);
 
   event->any.type = type;
   event->button.window = window;
@@ -882,7 +888,7 @@ fill_button_event (GdkWindow *window,
   event->button.y_root = y_root;
   /* FIXME event->axes */
   event->button.state = state;
-  event->button.button = button;
+  event->button.button = get_mouse_button_from_ns_event (nsevent);
   event->button.device = _gdk_display->core_pointer;
 }
 
@@ -895,22 +901,6 @@ fill_motion_event (GdkWindow *window,
                    gint       x_root,
                    gint       y_root)
 {
-  GdkModifierType state;
-
-  state = get_keyboard_modifiers_from_ns_event (nsevent);
-
-  switch ([nsevent type])
-    {
-    case NSLeftMouseDragged:
-    case NSRightMouseDragged:
-    case NSOtherMouseDragged:
-      state |= get_mouse_button_modifiers_from_ns_event (nsevent);
-      break;
-
-    case NSMouseMoved:
-      break;
-    }
-
   event->any.type = GDK_MOTION_NOTIFY;
   event->motion.window = window;
   event->motion.time = get_time_from_ns_event (nsevent);
@@ -919,7 +909,8 @@ fill_motion_event (GdkWindow *window,
   event->motion.x_root = x_root;
   event->motion.y_root = y_root;
   /* FIXME event->axes */
-  event->motion.state = state;
+  event->motion.state = get_keyboard_modifiers_from_ns_event (nsevent) |
+                        _gdk_quartz_events_get_current_mouse_modifiers ();
   event->motion.is_hint = FALSE;
   event->motion.device = _gdk_display->core_pointer;
 }
@@ -932,13 +923,12 @@ fill_scroll_event (GdkWindow          *window,
                    gint                y,
                    gint                x_root,
                    gint                y_root,
+                   gdouble             delta_x,
+                   gdouble             delta_y,
                    GdkScrollDirection  direction)
 {
-  GdkWindowObject *private;
   NSPoint point;
 
-  private = GDK_WINDOW_OBJECT (window);
-
   point = [nsevent locationInWindow];
 
   event->any.type = GDK_SCROLL;
@@ -951,6 +941,8 @@ fill_scroll_event (GdkWindow          *window,
   event->scroll.state = get_keyboard_modifiers_from_ns_event (nsevent);
   event->scroll.direction = direction;
   event->scroll.device = _gdk_display->core_pointer;
+  event->scroll.delta_x = delta_x;
+  event->scroll.delta_y = delta_y;
 }
 
 static void
@@ -960,7 +952,7 @@ fill_key_event (GdkWindow    *window,
                 GdkEventType  type)
 {
   GdkEventPrivate *priv;
-  GdkDeviceManagerCore *device_manager;
+  GdkQuartzDeviceManagerCore *device_manager;
   gchar buf[7];
   gunichar c = 0;
 
@@ -975,10 +967,10 @@ fill_key_event (GdkWindow    *window,
   event->key.group = ([nsevent modifierFlags] & NSAlternateKeyMask) ? 1 : 0;
   event->key.keyval = GDK_KEY_VoidSymbol;
 
-  device_manager = GDK_DEVICE_MANAGER_CORE (_gdk_display->device_manager);
+  device_manager = GDK_QUARTZ_DEVICE_MANAGER_CORE (_gdk_display->device_manager);
   gdk_event_set_device (event, device_manager->core_keyboard);
   
-  gdk_keymap_translate_keyboard_state (NULL,
+  gdk_keymap_translate_keyboard_state (gdk_keymap_get_for_display (_gdk_display),
                                       event->key.hardware_keycode,
                                       event->key.state, 
                                       event->key.group,
@@ -999,7 +991,7 @@ fill_key_event (GdkWindow    *window,
         {
         case GDK_KEY_Meta_R:
         case GDK_KEY_Meta_L:
-          mask = GDK_MOD1_MASK;
+          mask = GDK_MOD2_MASK;
           break;
         case GDK_KEY_Shift_R:
         case GDK_KEY_Shift_L:
@@ -1010,7 +1002,7 @@ fill_key_event (GdkWindow    *window,
           break;
         case GDK_KEY_Alt_R:
         case GDK_KEY_Alt_L:
-          mask = GDK_MOD5_MASK;
+          mask = GDK_MOD1_MASK;
           break;
         case GDK_KEY_Control_R:
         case GDK_KEY_Control_L:
@@ -1026,7 +1018,14 @@ fill_key_event (GdkWindow    *window,
         event->key.state |= mask;
     }
 
-  event->key.state |= current_button_state;
+  event->key.state |= _gdk_quartz_events_get_current_mouse_modifiers ();
+
+  /* The X11 backend adds the first virtual modifier MOD2..MOD5 are
+   * mapped to. Since we only have one virtual modifier in the quartz
+   * backend, calling the standard function will do.
+   */
+  gdk_keymap_add_virtual_modifiers (gdk_keymap_get_for_display (_gdk_display),
+                                    &event->key.state);
 
   event->key.string = NULL;
 
@@ -1083,17 +1082,13 @@ synthesize_crossing_event (GdkWindow *window,
                            gint       x_root,
                            gint       y_root)
 {
-  GdkWindowObject *private;
-
-  private = GDK_WINDOW_OBJECT (window);
-
   switch ([nsevent type])
     {
     case NSMouseEntered:
       /* Enter events are considered always to be from the root window as we
        * can't know for sure from what window we enter.
        */
-      if (!(private->event_mask & GDK_ENTER_NOTIFY_MASK))
+      if (!(window->event_mask & GDK_ENTER_NOTIFY_MASK))
         return FALSE;
 
       fill_crossing_event (window, event, nsevent,
@@ -1109,7 +1104,7 @@ synthesize_crossing_event (GdkWindow *window,
        * since there is no way to reliably get information about what new
        * window is entered when exiting one.
        */
-      if (!(private->event_mask & GDK_LEAVE_NOTIFY_MASK))
+      if (!(window->event_mask & GDK_LEAVE_NOTIFY_MASK))
         return FALSE;
 
       fill_crossing_event (window, event, nsevent,
@@ -1127,10 +1122,109 @@ synthesize_crossing_event (GdkWindow *window,
   return FALSE;
 }
 
-GdkEventMask 
-_gdk_quartz_events_get_current_event_mask (void)
+GdkModifierType
+_gdk_quartz_events_get_current_keyboard_modifiers (void)
 {
-  return current_event_mask;
+  if (gdk_quartz_osx_version () >= GDK_OSX_SNOW_LEOPARD)
+    {
+      return get_keyboard_modifiers_from_ns_flags ([NSClassFromString(@"NSEvent") modifierFlags]);
+    }
+  else
+    {
+      guint carbon_modifiers = GetCurrentKeyModifiers ();
+      GdkModifierType modifiers = 0;
+
+      if (carbon_modifiers & alphaLock)
+        modifiers |= GDK_LOCK_MASK;
+      if (carbon_modifiers & shiftKey)
+        modifiers |= GDK_SHIFT_MASK;
+      if (carbon_modifiers & controlKey)
+        modifiers |= GDK_CONTROL_MASK;
+      if (carbon_modifiers & optionKey)
+        modifiers |= GDK_MOD1_MASK;
+      if (carbon_modifiers & cmdKey)
+        modifiers |= GDK_MOD2_MASK;
+
+      return modifiers;
+    }
+}
+
+GdkModifierType
+_gdk_quartz_events_get_current_mouse_modifiers (void)
+{
+  if (gdk_quartz_osx_version () >= GDK_OSX_SNOW_LEOPARD)
+    {
+      return get_mouse_button_modifiers_from_ns_buttons ([NSClassFromString(@"NSEvent") pressedMouseButtons]);
+    }
+  else
+    {
+      return get_mouse_button_modifiers_from_ns_buttons (GetCurrentButtonState ());
+    }
+}
+
+/* Detect window resizing */
+
+static gboolean
+test_resize (NSEvent *event, GdkWindow *toplevel, gint x, gint y)
+{
+  GdkWindowImplQuartz *toplevel_impl;
+  gboolean lion;
+
+  /* Resizing from the resize indicator only begins if an NSLeftMouseButton
+   * event is received in the resizing area.
+   */
+  toplevel_impl = (GdkWindowImplQuartz *)toplevel->impl;
+  if ([toplevel_impl->toplevel showsResizeIndicator])
+  if ([event type] == NSLeftMouseDown &&
+      [toplevel_impl->toplevel showsResizeIndicator])
+    {
+      NSRect frame;
+
+      /* If the resize indicator is visible and the event
+       * is in the lower right 15x15 corner, we leave these
+       * events to Cocoa as to be handled as resize events.
+       * Applications may have widgets in this area.  These
+       * will most likely be larger than 15x15 and for
+       * scroll bars there are also other means to move
+       * the scroll bar.  Since the resize indicator is
+       * the only way of resizing windows on Mac OS, it
+       * is too important to not make functional.
+       */
+      frame = [toplevel_impl->view bounds];
+      if (x > frame.size.width - GRIP_WIDTH &&
+          x < frame.size.width &&
+          y > frame.size.height - GRIP_HEIGHT &&
+          y < frame.size.height)
+        return TRUE;
+     }
+
+  /* If we're on Lion and within 5 pixels of an edge,
+   * then assume that the user wants to resize, and
+   * return NULL to let Quartz get on with it. We check
+   * the selector isRestorable to see if we're on 10.7.
+   * This extra check is in case the user starts
+   * dragging before GDK recognizes the grab.
+   *
+   * We perform this check for a button press of all buttons, because we
+   * do receive, for instance, a right mouse down event for a GDK window
+   * for x-coordinate range [-3, 0], but we do not want to forward this
+   * into GDK. Forwarding such events into GDK will confuse the pointer
+   * window finding code, because there are no GdkWindows present in
+   * the range [-3, 0].
+   */
+  lion = gdk_quartz_osx_version () >= GDK_OSX_LION;
+  if (lion &&
+      ([event type] == NSLeftMouseDown ||
+       [event type] == NSRightMouseDown ||
+       [event type] == NSOtherMouseDown))
+    {
+      if (x < GDK_LION_RESIZE ||
+          x > toplevel->width - GDK_LION_RESIZE ||
+          y > toplevel->height - GDK_LION_RESIZE)
+        return TRUE;
+    }
+
+  return FALSE;
 }
 
 static gboolean
@@ -1151,7 +1245,7 @@ gdk_event_translate (GdkEvent *event,
   if (event_type == NSAppKitDefined)
     {
       if ([nsevent subtype] == NSApplicationDeactivatedEventType)
-        break_all_grabs (get_time_from_ns_event (nsevent));
+        _gdk_quartz_events_break_all_grabs (get_time_from_ns_event (nsevent));
 
       /* This could potentially be used to break grabs when clicking
        * on the title. The subtype 20 is undocumented so it's probably
@@ -1162,25 +1256,6 @@ gdk_event_translate (GdkEvent *event,
       return FALSE;
     }
 
-  /* Keep track of button state, since we don't get that information
-   * for key events. 
-   */
-  switch (event_type)
-    {
-    case NSLeftMouseDown:
-    case NSRightMouseDown:
-    case NSOtherMouseDown:
-      current_button_state |= get_mouse_button_modifiers_from_ns_event (nsevent);
-      break;
-    case NSLeftMouseUp:
-    case NSRightMouseUp:
-    case NSOtherMouseUp:
-      current_button_state &= ~get_mouse_button_modifiers_from_ns_event (nsevent);
-      break;
-    default:
-      break;
-    }
-
   if (_gdk_default_filters)
     {
       /* Apply global filters */
@@ -1196,20 +1271,49 @@ gdk_event_translate (GdkEvent *event,
 
   nswindow = [nsevent window];
 
-  /* Ignore events for no window or ones not created by GDK. */
-  if (!nswindow || ![[nswindow contentView] isKindOfClass:[GdkQuartzView class]])
+  /* Ignore events for windows not created by GDK. */
+  if (nswindow && ![[nswindow contentView] isKindOfClass:[GdkQuartzView class]])
     return FALSE;
 
+  /* Ignore events for ones with no windows */
+  if (!nswindow)
+    {
+      GdkWindow *toplevel = NULL;
+
+      if (event_type == NSMouseMoved)
+        {
+          /* Motion events received after clicking the menu bar do not have the
+           * window field set.  Instead of giving up on the event immediately,
+           * we first check whether this event is within our window bounds.
+           */
+          NSPoint screen_point = [NSEvent mouseLocation];
+          gint x_tmp, y_tmp;
+
+          toplevel = find_toplevel_under_pointer (_gdk_display,
+                                                  screen_point,
+                                                  &x_tmp, &y_tmp);
+        }
+
+      if (!toplevel)
+        return FALSE;
+    }
+
   /* Ignore events and break grabs while the window is being
    * dragged. This is a workaround for the window getting events for
    * the window title.
    */
-  if ([(GdkQuartzWindow *)nswindow isInMove])
+  if ([(GdkQuartzNSWindow *)nswindow isInMove])
     {
-      break_all_grabs (get_time_from_ns_event (nsevent));
+      _gdk_quartz_events_break_all_grabs (get_time_from_ns_event (nsevent));
       return FALSE;
     }
 
+  /* Also when in a manual resize, we ignore events so that these are
+   * pushed to GdkQuartzWindow's sendEvent handler.
+   */
+  if ([(GdkQuartzWindow *)nswindow isInManualResize])
+    return FALSE;
+
   /* Find the right GDK window to send the event to, taking grabs and
    * event masks into consideration.
    */
@@ -1217,17 +1321,20 @@ gdk_event_translate (GdkEvent *event,
   if (!window)
     return FALSE;
 
+  /* Quartz handles resizing on its own, so we want to stay out of the way. */
+  if (test_resize (nsevent, window, x, y))
+    return FALSE;
+
   /* Apply any window filters. */
   if (GDK_IS_WINDOW (window))
     {
-      GdkWindowObject *filter_private = (GdkWindowObject *) window;
       GdkFilterReturn result;
 
-      if (filter_private->filters)
+      if (window->filters)
        {
          g_object_ref (window);
 
-         result = gdk_event_apply_filters (nsevent, event, &filter_private->filters);
+         result = gdk_event_apply_filters (nsevent, event, &window->filters);
 
          g_object_unref (window);
 
@@ -1248,8 +1355,7 @@ gdk_event_translate (GdkEvent *event,
        event_type == NSOtherMouseDown ||
        event_type == NSLeftMouseDown))
     {
-      GdkWindowObject *private = (GdkWindowObject *)window;
-      GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);
+      GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (window->impl);
 
       if (![NSApp isActive])
         {
@@ -1267,8 +1373,6 @@ gdk_event_translate (GdkEvent *event,
         }
     }
 
-  current_event_mask = get_event_mask_from_ns_event (nsevent);
-
   return_val = TRUE;
 
   switch (event_type)
@@ -1291,28 +1395,66 @@ gdk_event_translate (GdkEvent *event,
 
     case NSScrollWheel:
       {
-       float dx = [nsevent deltaX];
-       float dy = [nsevent deltaY];
-       GdkScrollDirection direction;
+        GdkScrollDirection direction;
+       float dx;
+       float dy;
+#ifdef AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
+       if (gdk_quartz_osx_version() >= GDK_OSX_LION &&
+           [nsevent hasPreciseScrollingDeltas])
+         {
+           dx = [nsevent scrollingDeltaX];
+           dy = [nsevent scrollingDeltaY];
+            direction = GDK_SCROLL_SMOOTH;
 
-        if (dy != 0)
+            fill_scroll_event (window, event, nsevent, x, y, x_root, y_root,
+                               -dx, -dy, direction);
+
+            /* Fall through for scroll buttons emulation */
+         }
+#endif
+        dx = [nsevent deltaX];
+        dy = [nsevent deltaY];
+
+        if (dy != 0.0)
           {
             if (dy < 0.0)
               direction = GDK_SCROLL_DOWN;
             else
               direction = GDK_SCROLL_UP;
 
-            fill_scroll_event (window, event, nsevent, x, y, x_root, y_root, direction);
+            dy = fabs (dy);
+            dx = 0.0;
           }
-
-        if (dx != 0)
+        else if (dx != 0.0)
           {
             if (dx < 0.0)
               direction = GDK_SCROLL_RIGHT;
             else
               direction = GDK_SCROLL_LEFT;
 
-            fill_scroll_event (window, event, nsevent, x, y, x_root, y_root, direction);
+            dx = fabs (dx);
+            dy = 0.0;
+          }
+
+        if (dx != 0.0 || dy != 0.0)
+          {
+#ifdef AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
+           if (gdk_quartz_osx_version() >= GDK_OSX_LION &[nsevent hasPreciseScrollingDeltas])
+              {
+                GdkEvent *emulated_event;
+
+                emulated_event = gdk_event_new (GDK_SCROLL);
+                _gdk_event_set_pointer_emulated (emulated_event, TRUE);
+                fill_scroll_event (window, emulated_event, nsevent,
+                                   x, y, x_root, y_root,
+                                   dx, dy, direction);
+                append_event (emulated_event, TRUE);
+              }
+            else
+#endif
+              fill_scroll_event (window, event, nsevent,
+                                 x, y, x_root, y_root,
+                                 dx, dy, direction);
           }
       }
       break;
@@ -1363,7 +1505,7 @@ gdk_event_translate (GdkEvent *event,
 }
 
 void
-_gdk_events_queue (GdkDisplay *display)
+_gdk_quartz_display_queue_events (GdkDisplay *display)
 {  
   NSEvent *nsevent;
 
@@ -1393,9 +1535,9 @@ _gdk_events_queue (GdkDisplay *display)
          g_list_free_1 (node);
          gdk_event_free (event);
 
-          GDK_THREADS_LEAVE ();
+          gdk_threads_leave ();
           [NSApp sendEvent:nsevent];
-          GDK_THREADS_ENTER ();
+          gdk_threads_enter ();
         }
 
       _gdk_quartz_event_loop_release_event (nsevent);
@@ -1403,60 +1545,16 @@ _gdk_events_queue (GdkDisplay *display)
 }
 
 void
-gdk_flush (void)
-{
-  /* Not supported. */
-}
-
-void
-gdk_display_add_client_message_filter (GdkDisplay   *display,
-                                      GdkAtom       message_type,
-                                      GdkFilterFunc func,
-                                      gpointer      data)
-{
-  /* Not supported. */
-}
-
-void
-gdk_add_client_message_filter (GdkAtom       message_type,
-                              GdkFilterFunc func,
-                              gpointer      data)
-{
-  /* Not supported. */
-}
-
-void
-gdk_display_sync (GdkDisplay *display)
-{
-  /* Not supported. */
-}
-
-void
-gdk_display_flush (GdkDisplay *display)
+_gdk_quartz_screen_broadcast_client_message (GdkScreen *screen,
+                                             GdkEvent  *event)
 {
   /* Not supported. */
 }
 
 gboolean
-gdk_event_send_client_message_for_display (GdkDisplay      *display,
-                                          GdkEvent        *event,
-                                          GdkNativeWindow  winid)
-{
-  /* Not supported. */
-  return FALSE;
-}
-
-void
-gdk_screen_broadcast_client_message (GdkScreen *screen,
-                                    GdkEvent  *event)
-{
-  /* Not supported. */
-}
-
-gboolean
-gdk_screen_get_setting (GdkScreen   *screen,
-                       const gchar *name,
-                       GValue      *value)
+_gdk_quartz_screen_get_setting (GdkScreen   *screen,
+                                const gchar *name,
+                                GValue      *value)
 {
   if (strcmp (name, "gtk-double-click-time") == 0)
     {
@@ -1504,6 +1602,19 @@ gdk_screen_get_setting (GdkScreen   *screen,
 
       GDK_QUARTZ_RELEASE_POOL;
 
+      return TRUE;
+    }
+  else if (strcmp (name, "gtk-primary-button-warps-slider") == 0)
+    {
+      GDK_QUARTZ_ALLOC_POOL;
+
+      BOOL setting = [[NSUserDefaults standardUserDefaults] boolForKey:@"AppleScrollerPagingBehavior"];
+
+      /* If the Apple property is YES, it means "warp" */
+      g_value_set_boolean (value, setting == YES);
+
+      GDK_QUARTZ_RELEASE_POOL;
+
       return TRUE;
     }
   
@@ -1513,8 +1624,9 @@ gdk_screen_get_setting (GdkScreen   *screen,
 }
 
 void
-_gdk_windowing_event_data_copy (const GdkEvent *src,
-                                GdkEvent       *dst)
+_gdk_quartz_display_event_data_copy (GdkDisplay     *display,
+                                     const GdkEvent *src,
+                                     GdkEvent       *dst)
 {
   GdkEventPrivate *priv_src = (GdkEventPrivate *) src;
   GdkEventPrivate *priv_dst = (GdkEventPrivate *) dst;
@@ -1527,7 +1639,8 @@ _gdk_windowing_event_data_copy (const GdkEvent *src,
 }
 
 void
-_gdk_windowing_event_data_free (GdkEvent *event)
+_gdk_quartz_display_event_data_free (GdkDisplay *display,
+                                     GdkEvent   *event)
 {
   GdkEventPrivate *priv = (GdkEventPrivate *) event;