<commit_before>/* gdkevents-quartz.c
 *
 * Copyright (C) 1995-1997 <NAME>, <NAME> and <NAME>
 * Copyright (C) 1998-2002 <NAME>
 * Copyright (C) 2005-2008 Imendio AB
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * 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.
 */

#include "config.h"
#include <sys/types.h>
#include <sys/sysctl.h>
#include <pthread.h>
#include <unistd.h>

#import <Cocoa/Cocoa.h>
#include <Carbon/Carbon.h>

#include "gdkscreen.h"
#include "gdkkeysyms.h"
#include "gdkprivate-quartz.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 &&    \
     GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN &&  \
     GDK_WINDOW_TYPE (window) != GDK_WINDOW_OFFSCREEN)

/* 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;
}

void
_gdk_events_init (void)
{
  _gdk_quartz_event_loop_init ();

  current_keyboard_window = g_object_ref (_gdk_root);
}

gboolean
gdk_events_pending (void)
{
  return (_gdk_event_queue_find_first (_gdk_display) ||
	  (_gdk_quartz_event_loop_check_pending ()));
}

GdkEvent*
gdk_event_get_graphics_expose (GdkWindow *window)
{
  /* FIXME: Implement */
  return NULL;
}

GdkGrabStatus
gdk_keyboard_grab (GdkWindow  *window,
		   gint        owner_events,
		   guint32     time)
{
  GdkDisplay *display;
  GdkWindow  *toplevel;

  g_return_val_if_fail (window != NULL, 0);
  g_return_val_if_fail (GDK_IS_WINDOW (window), 0);

  display = gdk_drawable_get_display (window);
  toplevel = gdk_window_get_effective_toplevel (window);

  _gdk_display_set_has_keyboard_grab (display,
                                      window,
                                      toplevel,
                                      owner_events,
                                      0,
                                      time);

  return GDK_GRAB_SUCCESS;
}

void
gdk_display_keyboard_ungrab (GdkDisplay *display,
			     guint32     time)
{
  _gdk_display_unset_has_keyboard_grab (display, FALSE);
}

void
gdk_display_pointer_ungrab (GdkDisplay *display,
			    guint32     time)
{
  GdkPointerGrabInfo *grab;

  grab = _gdk_display_get_last_pointer_grab (display);
  if (grab)
    grab->serial_end = 0;

  _gdk_display_pointer_grab_update (display, 0);
}

GdkGrabStatus
_gdk_windowing_pointer_grab (GdkWindow    *window,
                             GdkWindow    *native,
                             gboolean	   owner_events,
                             GdkEventMask  event_mask,
                             GdkWindow    *confine_to,
                             GdkCursor    *cursor,
                             guint32       time)
{
  g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
  g_return_val_if_fail (confine_to == NULL || GDK_IS_WINDOW (confine_to), 0);

  _gdk_display_add_pointer_grab (_gdk_display,
                                 window,
                                 native,
                                 owner_events,
                                 event_mask,
                                 0,
                                 time,
                                 FALSE);

  return GDK_GRAB_SUCCESS;
}

static void
break_all_grabs (guint32 time)
{
  GdkPointerGrabInfo *grab;

  if (_gdk_display->keyboard_grab.window)
    _gdk_display_unset_has_keyboard_grab (_gdk_display, FALSE);

  grab = _gdk_display_get_last_pointer_grab (_gdk_display);
  if (grab)
    {
      grab->serial_end = 0;
      grab->implicit_ungrab = TRUE;
    }

  _gdk_display_pointer_grab_update (_gdk_display, 0);
}

static void
fixup_event (GdkEvent *event)
{
  if (event->any.window)
    g_object_ref (event->any.window);
  if (((event->any.type == GDK_ENTER_NOTIFY) ||
       (event->any.type == GDK_LEAVE_NOTIFY)) &&
      (event->crossing.subwindow != NULL))
    g_object_ref (event->crossing.subwindow);
  event->any.send_event = FALSE;
}

static void
append_event (GdkEvent *event,
              gboolean  windowing)
{
  GList *node;

  fixup_event (event);
  node = _gdk_event_queue_append (_gdk_display, event);

  if (windowing)
    _gdk_windowing_got_event (_gdk_display, node, event, 0);
}

static gint
gdk_event_apply_filters (NSEvent *nsevent,
			 GdkEvent *event,
			 GList *filters)
{
  GList *tmp_list;
  GdkFilterReturn result;
  
  tmp_list = filters;

  while (tmp_list)
    {
      GdkEventFilter *filter = (GdkEventFilter*) tmp_list->data;
      
      tmp_list = tmp_list->next;
      result = filter->function (nsevent, event, filter->data);
      if (result !=  GDK_FILTER_CONTINUE)
	return result;
    }

  return GDK_FILTER_CONTINUE;
}

static guint32
get_time_from_ns_event (NSEvent *event)
{
  double time = [event timestamp];
  
  return time * 1000.0;
}

static int
get_mouse_button_from_ns_event (NSEvent *event)
{
  NSInteger button;

  button = [event buttonNumber];

  switch (button)
    {
    case 0:
      return 1;
    case 1:
      return 3;
    case 2:
      return 2;
    default:
      return button + 1;
    }
}

static GdkModifierType
get_mouse_button_modifiers_from_ns_event (NSEvent *event)
{
  int button;
  GdkModifierType state = 0;

  /* This maps buttons 1 to 5 to GDK_BUTTON[1-5]_MASK */
  button = get_mouse_button_from_ns_event (event);
  if (button >= 1 && button <= 5)
    state = (1 << (button + 7));

  return state;
}

static GdkModifierType
get_keyboard_modifiers_from_ns_event (NSEvent *nsevent)
{
  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 & NSAlternateKeyMask)
    modifiers |= GDK_MOD1_MASK;
  if (nsflags & NSCommandKeyMask)
    modifiers |= GDK_MOD2_MASK;

  return modifiers;
}

/* Return an event mask from an NSEvent */
static GdkEventMask
get_event_mask_from_ns_event (NSEvent *nsevent)
{
  switch ([nsevent type])
    {
    case NSLeftMouseDown:
    case NSRightMouseDown:
    case NSOtherMouseDown:
      return GDK_BUTTON_PRESS_MASK;
    case NSLeftMouseUp:
    case NSRightMouseUp:
    case NSOtherMouseUp:
      return GDK_BUTTON_RELEASE_MASK;
    case NSMouseMoved:
      return GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK;
    case NSScrollWheel:
      /* Since applications that want button press events can get
       * scroll events on X11 (since scroll wheel events are really
       * button press events there), we need to use GDK_BUTTON_PRESS_MASK too.
       */
      return GDK_SCROLL_MASK | GDK_BUTTON_PRESS_MASK;
    case NSLeftMouseDragged:
      return (GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
	      GDK_BUTTON_MOTION_MASK | GDK_BUTTON1_MOTION_MASK | 
	      GDK_BUTTON1_MASK);
    case NSRightMouseDragged:
      return (GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
	      GDK_BUTTON_MOTION_MASK | GDK_BUTTON3_MOTION_MASK | 
	      GDK_BUTTON3_MASK);
    case NSOtherMouseDragged:
      {
	GdkEventMask mask;

	mask = (GDK_POINTER_MOTION_MASK |
		GDK_POINTER_MOTION_HINT_MASK |
		GDK_BUTTON_MOTION_MASK);

	if (get_mouse_button_from_ns_event (nsevent) == 2)
	  mask |= (GDK_BUTTON2_MOTION_MASK | GDK_BUTTON2_MOTION_MASK | 
		   GDK_BUTTON2_MASK);

	return mask;
      }
    case NSKeyDown:
    case NSKeyUp:
    case NSFlagsChanged:
      {
        switch (_gdk_quartz_keys_event_type (nsevent))
	  {
	  case GDK_KEY_PRESS:
	    return GDK_KEY_PRESS_MASK;
	  case GDK_KEY_RELEASE:
	    return GDK_KEY_RELEASE_MASK;
	  case GDK_NOTHING:
	    return 0;
	  default:
	    g_assert_not_reached ();
	  }
      }
      break;

    case NSMouseEntered:
      return GDK_ENTER_NOTIFY_MASK;

    case NSMouseExited:
      return GDK_LEAVE_NOTIFY_MASK;

    default:
      g_assert_not_reached ();
    }

  return 0;
}

static GdkEvent *
create_focus_event (GdkWindow *window,
		    gboolean   in)
{
  GdkEvent *event;

  event = gdk_event_new (GDK_FOCUS_CHANGE);
  event->focus_change.window = window;
  event->focus_change.in = in;

  return event;
}


static void
generate_motion_event (GdkWindow *window)
{
  NSPoint point;
  NSPoint screen_point;
  NSWindow *nswindow;
  GdkWindowObject *private;
  GdkEvent *event;
  gint x, y, x_root, y_root;

  event = gdk_event_new (GDK_MOTION_NOTIFY);
  event->any.window = NULL;
  event->any.send_event = TRUE;

  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;

  event->any.type = GDK_MOTION_NOTIFY;
  event->motion.window = window;
  event->motion.time = GDK_CURRENT_TIME;
  event->motion.x = x;
  event->motion.y = y;
  event->motion.x_root = x_root;
  event->motion.y_root = y_root;
  /* FIXME event->axes */
  event->motion.state = 0;
  event->motion.is_hint = FALSE;
  event->motion.device = _gdk_display->core_pointer;

  append_event (event, TRUE);
}

/* Note: Used to both set a new focus window and to unset the old one. */
void
_gdk_quartz_events_update_focus_window (GdkWindow *window,
					gboolean   got_focus)
{
  GdkEvent *event;

  if (got_focus && window == current_keyboard_window)
    return;

  /* FIXME: Don't do this when grabbed? Or make GdkQuartzWindow
   * disallow it in the first place instead?
   */
  
  if (!got_focus && window == current_keyboard_window)
    {
      event = create_focus_event (current_keyboard_window, FALSE);
      append_event (event, FALSE);
      g_object_unref (current_keyboard_window);
      current_keyboard_window = NULL;
    }

  if (got_focus)
    {
      if (current_keyboard_window)
	{
	  event = create_focus_event (current_keyboard_window, FALSE);
	  append_event (event, FALSE);
	  g_object_unref (current_keyboard_window);
	  current_keyboard_window = NULL;
	}
      
      event = create_focus_event (window, TRUE);
      append_event (event, FALSE);
      current_keyboard_window = g_object_ref (window);

      /* We just became the active window.  Unlike X11, Mac OS X does
       * not send us motion events while the window does not have focus
       * ("is not key").  We send a dummy motion notify event now, so that
       * everything in the window is set to correct state.
       */
      generate_motion_event (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;

  event = gdk_event_new (GDK_ENTER_NOTIFY);
  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;

  event->crossing.window = window;
  event->crossing.subwindow = NULL;
  event->crossing.time = GDK_CURRENT_TIME;
  event->crossing.x = x;
  event->crossing.y = y;
  event->crossing.x_root = x_root;
  event->crossing.y_root = y_root;
  event->crossing.mode = GDK_CROSSING_NORMAL;
  event->crossing.detail = GDK_NOTIFY_ANCESTOR;
  event->crossing.state = 0;

  append_event (event, TRUE);
}

void
_gdk_quartz_events_send_map_event (GdkWindow *window)
{
  GdkWindowObject *private = (GdkWindowObject *)window;
  GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);

  if (!impl->toplevel)
    return;

  if (private->event_mask & GDK_STRUCTURE_MASK)
    {
      GdkEvent event;

      event.any.type = GDK_MAP;
      event.any.window = window;
  
      gdk_event_put (&event);
    }
}

static GdkWindow *
find_toplevel_under_pointer (GdkDisplay *display,
                             NSPoint     screen_point,
                             gint       *x,
                             gint       *y)
{
  GdkWindow *toplevel;

  toplevel = display->pointer_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;
    }

  return toplevel;
}

/* This function finds the correct window to send an event to, taking
 * into account grabs, event propagation, and event masks.
 */
static GdkWindow *
find_window_for_ns_event (NSEvent *nsevent, 
                          gint    *x, 
                          gint    *y,
                          gint    *x_root,
                          gint    *y_root)
{
  GdkQuartzView *view;
  GdkWindow *toplevel;
  GdkWindowObject *private;
  NSPoint point;
  NSPoint screen_point;
  NSEventType event_type;

  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;

  _gdk_quartz_window_nspoint_to_gdk_xy (screen_point, x_root, y_root);

  event_type = [nsevent type];

  switch (event_type)
    {
    case NSLeftMouseDown:
    case NSRightMouseDown:
    case NSOtherMouseDown:
    case NSLeftMouseUp:
    case NSRightMouseUp:
    case NSOtherMouseUp:
    case NSMouseMoved:
    case NSScrollWheel:
    case NSLeftMouseDragged:
    case NSRightMouseDragged:
    case NSOtherMouseDragged:
      {
	GdkDisplay *display;
        GdkPointerGrabInfo *grab;

        display = gdk_drawable_get_display (toplevel);

	/* From the docs for XGrabPointer:
	 *
	 * If owner_events is True and if a generated pointer event
	 * would normally be reported to this client, it is reported
	 * as usual. Otherwise, the event is reported with respect to
	 * the grab_window and is reported only if selected by
	 * event_mask. For either value of owner_events, unreported
	 * events are discarded.
	 */
        grab = _gdk_display_get_last_pointer_grab (display);
	if (WINDOW_IS_TOPLEVEL (toplevel) && grab)
	  {
            /* Implicit grabs do not go through XGrabPointer and thus the
             * event mask should not be checked.
             */
	    if (!grab->implicit
                && (grab->event_mask & get_event_mask_from_ns_event (nsevent)) == 0)
              return NULL;

            if (grab->owner_events)
              {
                /* For owner events, we need to use the toplevel under the
                 * pointer, not the window from the NSEvent, since that is
                 * reported with respect to the key window, which could be
                 * wrong.
                 */
                GdkWindow *toplevel_under_pointer;
                gint x_tmp, y_tmp;

                toplevel_under_pointer = find_toplevel_under_pointer (display,
                                                                      screen_point,
                                                                      &x_tmp, &y_tmp);
                if (toplevel_under_pointer)
                  {
                    toplevel = toplevel_under_pointer;
                    *x = x_tmp;
                    *y = y_tmp;
                  }

                return toplevel;
              }
            else
              {
                /* 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;

		return grab_toplevel;
	      }

	    return NULL;<commit_msg>quartz: Separate out screen_point conversion in function<commit_after>/* gdkevents-quartz.c
 *
 * Copyright (C) 1995-1997 <NAME>, <NAME> and <NAME>
 * Copyright (C) 1998-2002 <NAME>
 * Copyright (C) 2005-2008 Imendio AB
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * 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.
 */

#include "config.h"
#include <sys/types.h>
#include <sys/sysctl.h>
#include <pthread.h>
#include <unistd.h>

#import <Cocoa/Cocoa.h>
#include <Carbon/Carbon.h>

#include "gdkscreen.h"
#include "gdkkeysyms.h"
#include "gdkprivate-quartz.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 &&    \
     GDK_WINDOW_TYPE (window) != GDK_WINDOW_FOREIGN &&  \
     GDK_WINDOW_TYPE (window) != GDK_WINDOW_OFFSCREEN)

/* 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;
}

void
_gdk_events_init (void)
{
  _gdk_quartz_event_loop_init ();

  current_keyboard_window = g_object_ref (_gdk_root);
}

gboolean
gdk_events_pending (void)
{
  return (_gdk_event_queue_find_first (_gdk_display) ||
	  (_gdk_quartz_event_loop_check_pending ()));
}

GdkEvent*
gdk_event_get_graphics_expose (GdkWindow *window)
{
  /* FIXME: Implement */
  return NULL;
}

GdkGrabStatus
gdk_keyboard_grab (GdkWindow  *window,
		   gint        owner_events,
		   guint32     time)
{
  GdkDisplay *display;
  GdkWindow  *toplevel;

  g_return_val_if_fail (window != NULL, 0);
  g_return_val_if_fail (GDK_IS_WINDOW (window), 0);

  display = gdk_drawable_get_display (window);
  toplevel = gdk_window_get_effective_toplevel (window);

  _gdk_display_set_has_keyboard_grab (display,
                                      window,
                                      toplevel,
                                      owner_events,
                                      0,
                                      time);

  return GDK_GRAB_SUCCESS;
}

void
gdk_display_keyboard_ungrab (GdkDisplay *display,
			     guint32     time)
{
  _gdk_display_unset_has_keyboard_grab (display, FALSE);
}

void
gdk_display_pointer_ungrab (GdkDisplay *display,
			    guint32     time)
{
  GdkPointerGrabInfo *grab;

  grab = _gdk_display_get_last_pointer_grab (display);
  if (grab)
    grab->serial_end = 0;

  _gdk_display_pointer_grab_update (display, 0);
}

GdkGrabStatus
_gdk_windowing_pointer_grab (GdkWindow    *window,
                             GdkWindow    *native,
                             gboolean	   owner_events,
                             GdkEventMask  event_mask,
                             GdkWindow    *confine_to,
                             GdkCursor    *cursor,
                             guint32       time)
{
  g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
  g_return_val_if_fail (confine_to == NULL || GDK_IS_WINDOW (confine_to), 0);

  _gdk_display_add_pointer_grab (_gdk_display,
                                 window,
                                 native,
                                 owner_events,
                                 event_mask,
                                 0,
                                 time,
                                 FALSE);

  return GDK_GRAB_SUCCESS;
}

static void
break_all_grabs (guint32 time)
{
  GdkPointerGrabInfo *grab;

  if (_gdk_display->keyboard_grab.window)
    _gdk_display_unset_has_keyboard_grab (_gdk_display, FALSE);

  grab = _gdk_display_get_last_pointer_grab (_gdk_display);
  if (grab)
    {
      grab->serial_end = 0;
      grab->implicit_ungrab = TRUE;
    }

  _gdk_display_pointer_grab_update (_gdk_display, 0);
}

static void
fixup_event (GdkEvent *event)
{
  if (event->any.window)
    g_object_ref (event->any.window);
  if (((event->any.type == GDK_ENTER_NOTIFY) ||
       (event->any.type == GDK_LEAVE_NOTIFY)) &&
      (event->crossing.subwindow != NULL))
    g_object_ref (event->crossing.subwindow);
  event->any.send_event = FALSE;
}

static void
append_event (GdkEvent *event,
              gboolean  windowing)
{
  GList *node;

  fixup_event (event);
  node = _gdk_event_queue_append (_gdk_display, event);

  if (windowing)
    _gdk_windowing_got_event (_gdk_display, node, event, 0);
}

static gint
gdk_event_apply_filters (NSEvent *nsevent,
			 GdkEvent *event,
			 GList *filters)
{
  GList *tmp_list;
  GdkFilterReturn result;
  
  tmp_list = filters;

  while (tmp_list)
    {
      GdkEventFilter *filter = (GdkEventFilter*) tmp_list->data;
      
      tmp_list = tmp_list->next;
      result = filter->function (nsevent, event, filter->data);
      if (result !=  GDK_FILTER_CONTINUE)
	return result;
    }

  return GDK_FILTER_CONTINUE;
}

static guint32
get_time_from_ns_event (NSEvent *event)
{
  double time = [event timestamp];
  
  return time * 1000.0;
}

static int
get_mouse_button_from_ns_event (NSEvent *event)
{
  NSInteger button;

  button = [event buttonNumber];

  switch (button)
    {
    case 0:
      return 1;
    case 1:
      return 3;
    case 2:
      return 2;
    default:
      return button + 1;
    }
}

static GdkModifierType
get_mouse_button_modifiers_from_ns_event (NSEvent *event)
{
  int button;
  GdkModifierType state = 0;

  /* This maps buttons 1 to 5 to GDK_BUTTON[1-5]_MASK */
  button = get_mouse_button_from_ns_event (event);
  if (button >= 1 && button <= 5)
    state = (1 << (button + 7));

  return state;
}

static GdkModifierType
get_keyboard_modifiers_from_ns_event (NSEvent *nsevent)
{
  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 & NSAlternateKeyMask)
    modifiers |= GDK_MOD1_MASK;
  if (nsflags & NSCommandKeyMask)
    modifiers |= GDK_MOD2_MASK;

  return modifiers;
}

/* Return an event mask from an NSEvent */
static GdkEventMask
get_event_mask_from_ns_event (NSEvent *nsevent)
{
  switch ([nsevent type])
    {
    case NSLeftMouseDown:
    case NSRightMouseDown:
    case NSOtherMouseDown:
      return GDK_BUTTON_PRESS_MASK;
    case NSLeftMouseUp:
    case NSRightMouseUp:
    case NSOtherMouseUp:
      return GDK_BUTTON_RELEASE_MASK;
    case NSMouseMoved:
      return GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK;
    case NSScrollWheel:
      /* Since applications that want button press events can get
       * scroll events on X11 (since scroll wheel events are really
       * button press events there), we need to use GDK_BUTTON_PRESS_MASK too.
       */
      return GDK_SCROLL_MASK | GDK_BUTTON_PRESS_MASK;
    case NSLeftMouseDragged:
      return (GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
	      GDK_BUTTON_MOTION_MASK | GDK_BUTTON1_MOTION_MASK | 
	      GDK_BUTTON1_MASK);
    case NSRightMouseDragged:
      return (GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
	      GDK_BUTTON_MOTION_MASK | GDK_BUTTON3_MOTION_MASK | 
	      GDK_BUTTON3_MASK);
    case NSOtherMouseDragged:
      {
	GdkEventMask mask;

	mask = (GDK_POINTER_MOTION_MASK |
		GDK_POINTER_MOTION_HINT_MASK |
		GDK_BUTTON_MOTION_MASK);

	if (get_mouse_button_from_ns_event (nsevent) == 2)
	  mask |= (GDK_BUTTON2_MOTION_MASK | GDK_BUTTON2_MOTION_MASK | 
		   GDK_BUTTON2_MASK);

	return mask;
      }
    case NSKeyDown:
    case NSKeyUp:
    case NSFlagsChanged:
      {
        switch (_gdk_quartz_keys_event_type (nsevent))
	  {
	  case GDK_KEY_PRESS:
	    return GDK_KEY_PRESS_MASK;
	  case GDK_KEY_RELEASE:
	    return GDK_KEY_RELEASE_MASK;
	  case GDK_NOTHING:
	    return 0;
	  default:
	    g_assert_not_reached ();
	  }
      }
      break;

    case NSMouseEntered:
      return GDK_ENTER_NOTIFY_MASK;

    case NSMouseExited:
      return GDK_LEAVE_NOTIFY_MASK;

    default:
      g_assert_not_reached ();
    }

  return 0;
}

static void
get_window_point_from_screen_point (GdkWindow *window,
                                    NSPoint    screen_point,
                                    gint      *x,
                                    gint      *y)
{
  NSPoint point;
  NSWindow *nswindow;
  GdkWindowObject *private;

  private = (GdkWindowObject *)window;
  nswindow = ((GdkWindowImplQuartz *)private->impl)->toplevel;

  point = [nswindow convertScreenToBase:screen_point];

  *x = point.x;
  *y = private->height - point.y;
}

static GdkEvent *
create_focus_event (GdkWindow *window,
		    gboolean   in)
{
  GdkEvent *event;

  event = gdk_event_new (GDK_FOCUS_CHANGE);
  event->focus_change.window = window;
  event->focus_change.in = in;

  return event;
}


static void
generate_motion_event (GdkWindow *window)
{
  NSPoint screen_point;
  GdkEvent *event;
  gint x, y, x_root, y_root;

  event = gdk_event_new (GDK_MOTION_NOTIFY);
  event->any.window = NULL;
  event->any.send_event = TRUE;

  screen_point = [NSEvent mouseLocation];

  _gdk_quartz_window_nspoint_to_gdk_xy (screen_point, &x_root, &y_root);
  get_window_point_from_screen_point (window, screen_point, &x, &y);

  event->any.type = GDK_MOTION_NOTIFY;
  event->motion.window = window;
  event->motion.time = GDK_CURRENT_TIME;
  event->motion.x = x;
  event->motion.y = y;
  event->motion.x_root = x_root;
  event->motion.y_root = y_root;
  /* FIXME event->axes */
  event->motion.state = 0;
  event->motion.is_hint = FALSE;
  event->motion.device = _gdk_display->core_pointer;

  append_event (event, TRUE);
}

/* Note: Used to both set a new focus window and to unset the old one. */
void
_gdk_quartz_events_update_focus_window (GdkWindow *window,
					gboolean   got_focus)
{
  GdkEvent *event;

  if (got_focus && window == current_keyboard_window)
    return;

  /* FIXME: Don't do this when grabbed? Or make GdkQuartzWindow
   * disallow it in the first place instead?
   */
  
  if (!got_focus && window == current_keyboard_window)
    {
      event = create_focus_event (current_keyboard_window, FALSE);
      append_event (event, FALSE);
      g_object_unref (current_keyboard_window);
      current_keyboard_window = NULL;
    }

  if (got_focus)
    {
      if (current_keyboard_window)
	{
	  event = create_focus_event (current_keyboard_window, FALSE);
	  append_event (event, FALSE);
	  g_object_unref (current_keyboard_window);
	  current_keyboard_window = NULL;
	}
      
      event = create_focus_event (window, TRUE);
      append_event (event, FALSE);
      current_keyboard_window = g_object_ref (window);

      /* We just became the active window.  Unlike X11, Mac OS X does
       * not send us motion events while the window does not have focus
       * ("is not key").  We send a dummy motion notify event now, so that
       * everything in the window is set to correct state.
       */
      generate_motion_event (window);
    }
}

void
_gdk_quartz_events_send_enter_notify_event (GdkWindow *window)
{
  NSPoint screen_point;
  GdkEvent *event;
  gint x, y, x_root, y_root;

  event = gdk_event_new (GDK_ENTER_NOTIFY);
  event->any.window = NULL;
  event->any.send_event = FALSE;

  screen_point = [NSEvent mouseLocation];

  _gdk_quartz_window_nspoint_to_gdk_xy (screen_point, &x_root, &y_root);
  get_window_point_from_screen_point (window, screen_point, &x, &y);

  event->crossing.window = window;
  event->crossing.subwindow = NULL;
  event->crossing.time = GDK_CURRENT_TIME;
  event->crossing.x = x;
  event->crossing.y = y;
  event->crossing.x_root = x_root;
  event->crossing.y_root = y_root;
  event->crossing.mode = GDK_CROSSING_NORMAL;
  event->crossing.detail = GDK_NOTIFY_ANCESTOR;
  event->crossing.state = 0;

  append_event (event, TRUE);
}

void
_gdk_quartz_events_send_map_event (GdkWindow *window)
{
  GdkWindowObject *private = (GdkWindowObject *)window;
  GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);

  if (!impl->toplevel)
    return;

  if (private->event_mask & GDK_STRUCTURE_MASK)
    {
      GdkEvent event;

      event.any.type = GDK_MAP;
      event.any.window = window;
  
      gdk_event_put (&event);
    }
}

static GdkWindow *
find_toplevel_under_pointer (GdkDisplay *display,
                             NSPoint     screen_point,
                             gint       *x,
                             gint       *y)
{
  GdkWindow *toplevel;

  toplevel = display->pointer_info.toplevel_under_pointer;
  if (toplevel && WINDOW_IS_TOPLEVEL (toplevel))
    get_window_point_from_screen_point (toplevel, screen_point, x, y);

  return toplevel;
}

/* This function finds the correct window to send an event to, taking
 * into account grabs, event propagation, and event masks.
 */
static GdkWindow *
find_window_for_ns_event (NSEvent *nsevent, 
                          gint    *x, 
                          gint    *y,
                          gint    *x_root,
                          gint    *y_root)
{
  GdkQuartzView *view;
  GdkWindow *toplevel;
  GdkWindowObject *private;
  NSPoint point;
  NSPoint screen_point;
  NSEventType event_type;

  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;

  _gdk_quartz_window_nspoint_to_gdk_xy (screen_point, x_root, y_root);

  event_type = [nsevent type];

  switch (event_type)
    {
    case NSLeftMouseDown:
    case NSRightMouseDown:
    case NSOtherMouseDown:
    case NSLeftMouseUp:
    case NSRightMouseUp:
    case NSOtherMouseUp:
    case NSMouseMoved:
    case NSScrollWheel:
    case NSLeftMouseDragged:
    case NSRightMouseDragged:
    case NSOtherMouseDragged:
      {
	GdkDisplay *display;
        GdkPointerGrabInfo *grab;

        display = gdk_drawable_get_display (toplevel);

	/* From the docs for XGrabPointer:
	 *
	 * If owner_events is True and if a generated pointer event
	 * would normally be reported to this client, it is reported
	 * as usual. Otherwise, the event is reported with respect to
	 * the grab_window and is reported only if selected by
	 * event_mask. For either value of owner_events, unreported
	 * events are discarded.
	 */
        grab = _gdk_display_get_last_pointer_grab (display);
	if (WINDOW_IS_TOPLEVEL (toplevel) && grab)
	  {
            /* Implicit grabs do not go through XGrabPointer and thus the
             * event mask should not be checked.
             */
	    if (!grab->implicit
                && (grab->event_mask & get_event_mask_from_ns_event (nsevent)) == 0)
              return NULL;

            if (grab->owner_events)
              {
                /* For owner events, we need to use the toplevel under the
                 * pointer, not the window from the NSEvent, since that is
                 * reported with respect to the key window, which could be
                 * wrong.
                 */
                GdkWindow *toplevel_under_pointer;
                gint x_tmp, y_tmp;

                toplevel_under_pointer = find_toplevel_under_pointer (display,
                                                                      screen_point,
                                                                      &x_tmp, &y_tmp);
                if (toplevel_under_pointer)
                  {
                    toplevel = toplevel_under_pointer;
                    *x = x_tmp;
                    *y = y_tmp;
                  }

                return toplevel;
              }
            else
              {
                /* Finally check the grab window. */
		GdkWindow *grab_toplevel;

		grab_toplevel = gdk_window_get_effective_toplevel (grab->window);
                get_window_point_from_screen_point (grab_toplevel,
                                                    screen_point, x, y);

		return grab_toplevel;
	      }

	    return NULL;
{'fraction_non_alphanumeric': 0.08307014748065947, 'fraction_numerical': 0.0062585112856025265, 'mean_word_length': 2.585497610637856, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 146, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 45, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2241894', 'n_tokens_mistral': 12070, 'n_tokens_neox': 11516, 'n_words': 2665}