[gtk+/events-refactor: 322/1085] Rip out some gdkevents-x11 code into GdkDeviceManagerCore.



commit 7dfbe5cc85b5140f5619f5533cf4ffd9cace38f7
Author: Carlos Garnacho <carlosg gnome org>
Date:   Thu May 28 01:45:02 2009 +0200

    Rip out some gdkevents-x11 code into GdkDeviceManagerCore.
    
    GdkDeviceManagerCore now implements the GdkEventTranslator interface, code was
    taken from gdkevents-x11.c so it translates XEvents related to input devices
    into GdkEvents.

 gdk/x11/gdkdevicemanager-core.c | 1027 ++++++++++++++++++++++++++++++++++++++-
 1 files changed, 1026 insertions(+), 1 deletions(-)
---
diff --git a/gdk/x11/gdkdevicemanager-core.c b/gdk/x11/gdkdevicemanager-core.c
index 37cdb87..2624847 100644
--- a/gdk/x11/gdkdevicemanager-core.c
+++ b/gdk/x11/gdkdevicemanager-core.c
@@ -20,7 +20,17 @@
 #include <gdk/gdktypes.h>
 #include <gdk/gdkdevicemanager.h>
 #include "gdkdevicemanager-core.h"
+#include "gdkeventtranslator.h"
 #include "gdkinputprivate.h"
+#include "gdkkeysyms.h"
+
+#ifdef HAVE_XKB
+#include <X11/XKBlib.h>
+#endif
+
+
+#define HAS_FOCUS(toplevel)                           \
+  ((toplevel)->has_focus || (toplevel)->has_pointer_focus)
 
 static GdkDeviceAxis gdk_input_core_axes[] = {
   { GDK_AXIS_X, 0, 0 },
@@ -30,8 +40,17 @@ static GdkDeviceAxis gdk_input_core_axes[] = {
 static GList * gdk_device_manager_core_get_devices (GdkDeviceManager *device_manager,
                                                     GdkDeviceType     type);
 
+static void     gdk_device_manager_event_translator_init (GdkEventTranslatorIface *iface);
+
+static gboolean gdk_device_manager_translate_event (GdkEventTranslator *translator,
+                                                    GdkDisplay         *display,
+                                                    GdkEvent           *event,
+                                                    XEvent             *xevent);
 
-G_DEFINE_TYPE (GdkDeviceManagerCore, gdk_device_manager_core, GDK_TYPE_DEVICE_MANAGER)
+
+G_DEFINE_TYPE_WITH_CODE (GdkDeviceManagerCore, gdk_device_manager_core, GDK_TYPE_DEVICE_MANAGER,
+                         G_IMPLEMENT_INTERFACE (GDK_TYPE_EVENT_TRANSLATOR,
+                                                gdk_device_manager_event_translator_init))
 
 static void
 gdk_device_manager_core_class_init (GdkDeviceManagerCoreClass *klass)
@@ -41,6 +60,12 @@ gdk_device_manager_core_class_init (GdkDeviceManagerCoreClass *klass)
   device_manager_class->get_devices = gdk_device_manager_core_get_devices;
 }
 
+static void
+gdk_device_manager_event_translator_init (GdkEventTranslatorIface *iface)
+{
+  iface->translate_event = gdk_device_manager_translate_event;
+}
+
 static GdkDevice *
 create_core_pointer (GdkDisplay *display)
 {
@@ -73,6 +98,1006 @@ gdk_device_manager_core_init (GdkDeviceManagerCore *device_manager)
   device_manager->core_pointer = create_core_pointer (display);
 }
 
+static void
+get_real_window (GdkDisplay  *display,
+		 XEvent      *event,
+                 GdkWindow  **event_window,
+                 GdkWindow  **filter_window)
+{
+  Window event_xwindow, filter_xwindow;
+
+  event_xwindow = None;
+  filter_xwindow = None;
+
+  /* Core events all have an event->xany.window field, but that's
+   * not true for extension events
+   */
+  if (event->type >= KeyPress &&
+      event->type <= MappingNotify)
+    {
+      filter_xwindow = event->xany.window;
+      switch (event->type)
+	{
+	case CreateNotify:
+	  event_xwindow = event->xcreatewindow.window;
+	  break;
+	case DestroyNotify:
+	  event_xwindow = event->xdestroywindow.window;
+	  break;
+	case UnmapNotify:
+	  event_xwindow = event->xunmap.window;
+	  break;
+	case MapNotify:
+	  event_xwindow = event->xmap.window;
+	  break;
+	case MapRequest:
+	  event_xwindow = event->xmaprequest.window;
+	  break;
+	case ReparentNotify:
+	  event_xwindow = event->xreparent.window;
+	  break;
+	case ConfigureNotify:
+	  event_xwindow = event->xconfigure.window;
+	  break;
+	case ConfigureRequest:
+	  event_xwindow = event->xconfigurerequest.window;
+	  break;
+	case GravityNotify:
+	  event_xwindow = event->xgravity.window;
+	  break;
+	case CirculateNotify:
+	  event_xwindow = event->xcirculate.window;
+	  break;
+	case CirculateRequest:
+	  event_xwindow = event->xcirculaterequest.window;
+	  break;
+	default:
+	  event_xwindow = event->xany.window;
+	}
+    }
+#if 0
+  else
+    {
+      GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+      GSList *tmp_list;
+
+      for (tmp_list = display_x11->event_types;
+	   tmp_list;
+	   tmp_list = tmp_list->next)
+	{
+	  GdkEventTypeX11 *event_type = tmp_list->data;
+
+	  if (event->type >= event_type->base &&
+	      event->type < event_type->base + event_type->n_events)
+	    {
+	      *event_xwindow = event->xany.window;
+	      *filter_xwindow = event->xany.window;
+	    }
+	}
+    }
+#endif
+
+  /* Now find out the corresponding GdkWindows */
+  *event_window = gdk_window_lookup_for_display (display, event_xwindow);
+
+  /* We may receive events such as NoExpose/GraphicsExpose
+   * and ShmCompletion for pixmaps
+   */
+  if (*event_window && !GDK_IS_WINDOW (*event_window))
+    *event_window = NULL;
+
+  /* We always run the filters for the window where the event
+   * is delivered, not the window that it relates to
+   */
+  if (filter_xwindow == event_xwindow)
+    *filter_window = *event_window;
+  else
+    {
+      *filter_window = gdk_window_lookup_for_display (display, filter_xwindow);
+
+      if (*filter_window && !GDK_IS_WINDOW (*filter_window))
+	*filter_window = NULL;
+    }
+}
+
+static void
+translate_key_event (GdkDisplay *display,
+		     GdkEvent   *event,
+		     XEvent     *xevent)
+{
+  GdkKeymap *keymap = gdk_keymap_get_for_display (display);
+  gunichar c = 0;
+  gchar buf[7];
+
+  event->key.type = xevent->xany.type == KeyPress ? GDK_KEY_PRESS : GDK_KEY_RELEASE;
+  event->key.time = xevent->xkey.time;
+
+  event->key.state = (GdkModifierType) xevent->xkey.state;
+  event->key.group = _gdk_x11_get_group_for_state (display, xevent->xkey.state);
+  event->key.hardware_keycode = xevent->xkey.keycode;
+
+  event->key.keyval = GDK_VoidSymbol;
+
+  gdk_keymap_translate_keyboard_state (keymap,
+				       event->key.hardware_keycode,
+				       event->key.state,
+				       event->key.group,
+				       &event->key.keyval,
+				       NULL, NULL, NULL);
+
+  _gdk_keymap_add_virtual_modifiers (keymap, &event->key.state);
+  event->key.is_modifier = _gdk_keymap_key_is_modifier (keymap, event->key.hardware_keycode);
+
+  /* Fill in event->string crudely, since various programs
+   * depend on it.
+   */
+  event->key.string = NULL;
+
+  if (event->key.keyval != GDK_VoidSymbol)
+    c = gdk_keyval_to_unicode (event->key.keyval);
+
+  if (c)
+    {
+      gsize bytes_written;
+      gint len;
+
+      /* Apply the control key - Taken from Xlib
+       */
+      if (event->key.state & GDK_CONTROL_MASK)
+	{
+	  if ((c >= '@' && c < '\177') || c == ' ') c &= 0x1F;
+	  else if (c == '2')
+	    {
+	      event->key.string = g_memdup ("\0\0", 2);
+	      event->key.length = 1;
+	      buf[0] = '\0';
+	      goto out;
+	    }
+	  else if (c >= '3' && c <= '7') c -= ('3' - '\033');
+	  else if (c == '8') c = '\177';
+	  else if (c == '/') c = '_' & 0x1F;
+	}
+
+      len = g_unichar_to_utf8 (c, buf);
+      buf[len] = '\0';
+
+      event->key.string = g_locale_from_utf8 (buf, len,
+					      NULL, &bytes_written,
+					      NULL);
+      if (event->key.string)
+	event->key.length = bytes_written;
+    }
+  else if (event->key.keyval == GDK_Escape)
+    {
+      event->key.length = 1;
+      event->key.string = g_strdup ("\033");
+    }
+  else if (event->key.keyval == GDK_Return ||
+	  event->key.keyval == GDK_KP_Enter)
+    {
+      event->key.length = 1;
+      event->key.string = g_strdup ("\r");
+    }
+
+  if (!event->key.string)
+    {
+      event->key.length = 0;
+      event->key.string = g_strdup ("");
+    }
+
+ out:
+#ifdef G_ENABLE_DEBUG
+  if (_gdk_debug_flags & GDK_DEBUG_EVENTS)
+    {
+      g_message ("%s:\t\twindow: %ld	 key: %12s  %d",
+		 event->type == GDK_KEY_PRESS ? "key press  " : "key release",
+		 xevent->xkey.window,
+		 event->key.keyval ? gdk_keyval_name (event->key.keyval) : "(none)",
+		 event->key.keyval);
+
+      if (event->key.length > 0)
+	g_message ("\t\tlength: %4d string: \"%s\"",
+		   event->key.length, buf);
+    }
+#endif /* G_ENABLE_DEBUG */
+  return;
+}
+
+#ifdef G_ENABLE_DEBUG
+static const char notify_modes[][19] = {
+  "NotifyNormal",
+  "NotifyGrab",
+  "NotifyUngrab",
+  "NotifyWhileGrabbed"
+};
+
+static const char notify_details[][23] = {
+  "NotifyAncestor",
+  "NotifyVirtual",
+  "NotifyInferior",
+  "NotifyNonlinear",
+  "NotifyNonlinearVirtual",
+  "NotifyPointer",
+  "NotifyPointerRoot",
+  "NotifyDetailNone"
+};
+#endif
+
+static void
+set_user_time (GdkWindow *window,
+	       GdkEvent  *event)
+{
+  g_return_if_fail (event != NULL);
+
+  window = gdk_window_get_toplevel (event->client.window);
+  g_return_if_fail (GDK_IS_WINDOW (window));
+
+  /* If an event doesn't have a valid timestamp, we shouldn't use it
+   * to update the latest user interaction time.
+   */
+  if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
+    gdk_x11_window_set_user_time (gdk_window_get_toplevel (window),
+                                  gdk_event_get_time (event));
+}
+
+static void
+generate_focus_event (GdkWindow *window,
+		      gboolean   in)
+{
+  GdkEvent event;
+
+  event.type = GDK_FOCUS_CHANGE;
+  event.focus_change.window = window;
+  event.focus_change.send_event = FALSE;
+  event.focus_change.in = in;
+
+  gdk_event_put (&event);
+}
+
+static gboolean
+set_screen_from_root (GdkDisplay *display,
+		      GdkEvent   *event,
+		      Window      xrootwin)
+{
+  GdkScreen *screen;
+
+  screen = _gdk_x11_display_screen_for_xrootwin (display, xrootwin);
+
+  if (screen)
+    {
+      gdk_event_set_screen (event, screen);
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gboolean
+gdk_device_manager_translate_event (GdkEventTranslator *translator,
+                                    GdkDisplay         *display,
+                                    GdkEvent           *event,
+                                    XEvent             *xevent)
+{
+  GdkDeviceManagerCore *device_manager;
+  GdkWindow *window;
+  GdkWindowObject *window_private;
+  GdkWindow *filter_window;
+  GdkWindowImplX11 *window_impl = NULL;
+  gboolean return_val;
+  gint xoffset = 0, yoffset = 0;
+  GdkScreen *screen = NULL;
+  GdkScreenX11 *screen_x11 = NULL;
+  GdkToplevelX11 *toplevel = NULL;
+  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+
+  device_manager = GDK_DEVICE_MANAGER_CORE (translator);
+  return_val = FALSE;
+
+  /* init these, since the done: block uses them */
+  window = NULL;
+  window_private = NULL;
+  event->any.window = NULL;
+
+  /* Run default filters */
+#if 0
+  if (_gdk_default_filters)
+    {
+      /* Apply global filters */
+      GdkFilterReturn result;
+      result = gdk_event_apply_filters (xevent, event,
+                                        _gdk_default_filters);
+
+      if (result != GDK_FILTER_CONTINUE)
+        {
+          return_val = (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
+          goto done;
+        }
+    }
+#endif
+
+  /* Find the GdkWindow that this event relates to.
+   * Basically this means substructure events
+   * are reported same as structure events
+   */
+  get_real_window (display, xevent, &window, &filter_window);
+  window_private = (GdkWindowObject *) window;
+
+  if (window)
+    {
+      screen = GDK_WINDOW_SCREEN (window);
+      screen_x11 = GDK_SCREEN_X11 (screen);
+      toplevel = _gdk_x11_window_get_toplevel (window);
+
+      window_impl = GDK_WINDOW_IMPL_X11 (window_private->impl);
+
+      /* Move key events on focus window to the real toplevel, and
+       * filter out all other events on focus window
+       */
+      /* FIXME: is this needed? */
+#if 0
+      if (toplevel && xwindow == toplevel->focus_window)
+	{
+	  switch (xevent->type)
+	    {
+	    case KeyPress:
+	    case KeyRelease:
+	      xwindow = GDK_WINDOW_XID (window);
+	      xevent->xany.window = xwindow;
+	      break;
+	    default:
+	      return FALSE;
+	    }
+	}
+#endif
+
+      g_object_ref (window);
+    }
+
+  event->any.window = window;
+  event->any.send_event = xevent->xany.send_event ? TRUE : FALSE;
+
+  if (window_private && GDK_WINDOW_DESTROYED (window))
+    {
+      if (xevent->type != DestroyNotify)
+	{
+	  return_val = FALSE;
+	  goto done;
+	}
+    }
+#if 0
+  else if (filter_window)
+    {
+      /* Apply per-window filters */
+      GdkWindowObject *filter_private = (GdkWindowObject *) filter_window;
+      GdkFilterReturn result;
+
+      if (filter_private->filters)
+	{
+	  g_object_ref (filter_window);
+
+	  result = gdk_event_apply_filters (xevent, event,
+					    filter_private->filters);
+
+	  g_object_unref (filter_window);
+
+	  if (result != GDK_FILTER_CONTINUE)
+	    {
+	      return_val = (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
+	      goto done;
+	    }
+	}
+    }
+#endif
+
+#if 0
+  if (screen_x11 && screen_x11->wmspec_check_window != None &&
+      xwindow == screen_x11->wmspec_check_window)
+    {
+      if (xevent->type == DestroyNotify)
+        {
+          screen_x11->wmspec_check_window = None;
+          g_free (screen_x11->window_manager_name);
+          screen_x11->window_manager_name = g_strdup ("unknown");
+
+          /* careful, reentrancy */
+          _gdk_x11_screen_window_manager_changed (GDK_SCREEN (screen_x11));
+        }
+
+      /* Eat events on this window unless someone had wrapped
+       * it as a foreign window
+       */
+      if (window == NULL)
+	{
+	  return_val = FALSE;
+	  goto done;
+	}
+    }
+#endif
+
+  if (window &&
+      (xevent->type == MotionNotify ||
+       xevent->type == ButtonRelease))
+    {
+      if (_gdk_moveresize_handle_event (xevent))
+	{
+          return_val = FALSE;
+          goto done;
+        }
+    }
+
+  /* We do a "manual" conversion of the XEvent to a
+   *  GdkEvent. The structures are mostly the same so
+   *  the conversion is fairly straightforward. We also
+   *  optionally print debugging info regarding events
+   *  received.
+   */
+
+  return_val = TRUE;
+
+  if (window)
+    _gdk_x11_window_get_offsets (window, &xoffset, &yoffset);
+
+  switch (xevent->type)
+    {
+    case KeyPress:
+      if (window_private == NULL)
+        {
+          return_val = FALSE;
+          break;
+        }
+      translate_key_event (display, event, xevent);
+      set_user_time (window, event);
+      break;
+
+    case KeyRelease:
+      if (window_private == NULL)
+        {
+          return_val = FALSE;
+          break;
+        }
+
+      /* Emulate detectable auto-repeat by checking to see
+       * if the next event is a key press with the same
+       * keycode and timestamp, and if so, ignoring the event.
+       */
+
+      if (!display_x11->have_xkb_autorepeat && XPending (xevent->xkey.display))
+	{
+	  XEvent next_event;
+
+	  XPeekEvent (xevent->xkey.display, &next_event);
+
+	  if (next_event.type == KeyPress &&
+	      next_event.xkey.keycode == xevent->xkey.keycode &&
+	      next_event.xkey.time == xevent->xkey.time)
+	    {
+	      return_val = FALSE;
+	      break;
+	    }
+	}
+
+      translate_key_event (display, event, xevent);
+      break;
+
+    case ButtonPress:
+      GDK_NOTE (EVENTS,
+		g_message ("button press:\t\twindow: %ld  x,y: %d %d  button: %d",
+			   xevent->xbutton.window,
+			   xevent->xbutton.x, xevent->xbutton.y,
+			   xevent->xbutton.button));
+
+      if (window_private == NULL ||
+	  ((window_private->extension_events != 0) &&
+           display_x11->input_ignore_core))
+	{
+	  return_val = FALSE;
+	  break;
+	}
+
+      /* If we get a ButtonPress event where the button is 4 or 5,
+	 it's a Scroll event */
+      switch (xevent->xbutton.button)
+        {
+        case 4: /* up */
+        case 5: /* down */
+        case 6: /* left */
+        case 7: /* right */
+	  event->scroll.type = GDK_SCROLL;
+
+          if (xevent->xbutton.button == 4)
+            event->scroll.direction = GDK_SCROLL_UP;
+          else if (xevent->xbutton.button == 5)
+            event->scroll.direction = GDK_SCROLL_DOWN;
+          else if (xevent->xbutton.button == 6)
+            event->scroll.direction = GDK_SCROLL_LEFT;
+          else
+            event->scroll.direction = GDK_SCROLL_RIGHT;
+
+	  event->scroll.window = window;
+	  event->scroll.time = xevent->xbutton.time;
+	  event->scroll.x = xevent->xbutton.x + xoffset;
+	  event->scroll.y = xevent->xbutton.y + yoffset;
+	  event->scroll.x_root = (gfloat) xevent->xbutton.x_root;
+	  event->scroll.y_root = (gfloat) xevent->xbutton.y_root;
+	  event->scroll.state = (GdkModifierType) xevent->xbutton.state;
+	  event->scroll.device = device_manager->core_pointer;
+
+	  if (!set_screen_from_root (display, event, xevent->xbutton.root))
+	    {
+	      return_val = FALSE;
+	      break;
+	    }
+
+          break;
+
+        default:
+	  event->button.type = GDK_BUTTON_PRESS;
+	  event->button.window = window;
+	  event->button.time = xevent->xbutton.time;
+	  event->button.x = xevent->xbutton.x + xoffset;
+	  event->button.y = xevent->xbutton.y + yoffset;
+	  event->button.x_root = (gfloat) xevent->xbutton.x_root;
+	  event->button.y_root = (gfloat) xevent->xbutton.y_root;
+	  event->button.axes = NULL;
+	  event->button.state = (GdkModifierType) xevent->xbutton.state;
+	  event->button.button = xevent->xbutton.button;
+	  event->button.device = device_manager->core_pointer;
+
+	  if (!set_screen_from_root (display, event, xevent->xbutton.root))
+	    {
+	      return_val = FALSE;
+	      break;
+	    }
+
+	  _gdk_event_button_generate (display, event);
+          break;
+	}
+
+      set_user_time (window, event);
+
+      _gdk_xgrab_check_button_event (window, xevent);
+      break;
+
+    case ButtonRelease:
+      GDK_NOTE (EVENTS,
+		g_message ("button release:\twindow: %ld  x,y: %d %d  button: %d",
+			   xevent->xbutton.window,
+			   xevent->xbutton.x, xevent->xbutton.y,
+			   xevent->xbutton.button));
+
+      if (window_private == NULL ||
+	  ((window_private->extension_events != 0) &&
+           display_x11->input_ignore_core))
+	{
+	  return_val = FALSE;
+	  break;
+	}
+
+      /* We treat button presses as scroll wheel events, so ignore the release */
+      if (xevent->xbutton.button == 4 || xevent->xbutton.button == 5 ||
+          xevent->xbutton.button == 6 || xevent->xbutton.button == 7)
+	{
+	  return_val = FALSE;
+	  break;
+	}
+
+      event->button.type = GDK_BUTTON_RELEASE;
+      event->button.window = window;
+      event->button.time = xevent->xbutton.time;
+      event->button.x = xevent->xbutton.x + xoffset;
+      event->button.y = xevent->xbutton.y + yoffset;
+      event->button.x_root = (gfloat) xevent->xbutton.x_root;
+      event->button.y_root = (gfloat) xevent->xbutton.y_root;
+      event->button.axes = NULL;
+      event->button.state = (GdkModifierType) xevent->xbutton.state;
+      event->button.button = xevent->xbutton.button;
+      event->button.device = device_manager->core_pointer;
+
+      if (!set_screen_from_root (display, event, xevent->xbutton.root))
+	{
+	  return_val = FALSE;
+	  break;
+	}
+
+      _gdk_xgrab_check_button_event (window, xevent);
+      break;
+
+    case MotionNotify:
+      GDK_NOTE (EVENTS,
+		g_message ("motion notify:\t\twindow: %ld  x,y: %d %d  hint: %s",
+			   xevent->xmotion.window,
+			   xevent->xmotion.x, xevent->xmotion.y,
+			   (xevent->xmotion.is_hint) ? "true" : "false"));
+
+      if (window_private == NULL ||
+	  ((window_private->extension_events != 0) &&
+           display_x11->input_ignore_core))
+	{
+	  return_val = FALSE;
+	  break;
+	}
+
+      event->motion.type = GDK_MOTION_NOTIFY;
+      event->motion.window = window;
+      event->motion.time = xevent->xmotion.time;
+      event->motion.x = xevent->xmotion.x + xoffset;
+      event->motion.y = xevent->xmotion.y + yoffset;
+      event->motion.x_root = (gfloat) xevent->xmotion.x_root;
+      event->motion.y_root = (gfloat) xevent->xmotion.y_root;
+      event->motion.axes = NULL;
+      event->motion.state = (GdkModifierType) xevent->xmotion.state;
+      event->motion.is_hint = xevent->xmotion.is_hint;
+      event->motion.device = device_manager->core_pointer;
+
+      if (!set_screen_from_root (display, event, xevent->xbutton.root))
+	{
+	  return_val = FALSE;
+	  break;
+	}
+
+      break;
+
+    case EnterNotify:
+      GDK_NOTE (EVENTS,
+		g_message ("enter notify:\t\twindow: %ld  detail: %d subwin: %ld",
+			   xevent->xcrossing.window,
+			   xevent->xcrossing.detail,
+			   xevent->xcrossing.subwindow));
+
+      if (window_private == NULL)
+        {
+          return_val = FALSE;
+          break;
+        }
+
+      if (!set_screen_from_root (display, event, xevent->xbutton.root))
+	{
+	  return_val = FALSE;
+	  break;
+	}
+
+      /* Handle focusing (in the case where no window manager is running */
+      if (toplevel && xevent->xcrossing.detail != NotifyInferior)
+	{
+	  toplevel->has_pointer = TRUE;
+
+	  if (xevent->xcrossing.focus && !toplevel->has_focus_window)
+	    {
+	      gboolean had_focus = HAS_FOCUS (toplevel);
+
+	      toplevel->has_pointer_focus = TRUE;
+
+	      if (HAS_FOCUS (toplevel) != had_focus)
+		generate_focus_event (window, TRUE);
+	    }
+	}
+
+      /* Tell XInput stuff about it if appropriate */
+      if (window_private &&
+	  !GDK_WINDOW_DESTROYED (window) &&
+	  window_private->extension_events != 0)
+	_gdk_input_enter_event (&xevent->xcrossing, window);
+
+      event->crossing.type = GDK_ENTER_NOTIFY;
+      event->crossing.window = window;
+
+      /* If the subwindow field of the XEvent is non-NULL, then
+       *  lookup the corresponding GdkWindow.
+       */
+      if (xevent->xcrossing.subwindow != None)
+	event->crossing.subwindow = gdk_window_lookup_for_display (display, xevent->xcrossing.subwindow);
+      else
+	event->crossing.subwindow = NULL;
+
+      event->crossing.time = xevent->xcrossing.time;
+      event->crossing.x = xevent->xcrossing.x + xoffset;
+      event->crossing.y = xevent->xcrossing.y + yoffset;
+      event->crossing.x_root = xevent->xcrossing.x_root;
+      event->crossing.y_root = xevent->xcrossing.y_root;
+
+      /* Translate the crossing mode into Gdk terms.
+       */
+      switch (xevent->xcrossing.mode)
+	{
+	case NotifyNormal:
+	  event->crossing.mode = GDK_CROSSING_NORMAL;
+	  break;
+	case NotifyGrab:
+	  event->crossing.mode = GDK_CROSSING_GRAB;
+	  break;
+	case NotifyUngrab:
+	  event->crossing.mode = GDK_CROSSING_UNGRAB;
+	  break;
+	};
+
+      /* Translate the crossing detail into Gdk terms.
+       */
+      switch (xevent->xcrossing.detail)
+	{
+	case NotifyInferior:
+	  event->crossing.detail = GDK_NOTIFY_INFERIOR;
+	  break;
+	case NotifyAncestor:
+	  event->crossing.detail = GDK_NOTIFY_ANCESTOR;
+	  break;
+	case NotifyVirtual:
+	  event->crossing.detail = GDK_NOTIFY_VIRTUAL;
+	  break;
+	case NotifyNonlinear:
+	  event->crossing.detail = GDK_NOTIFY_NONLINEAR;
+	  break;
+	case NotifyNonlinearVirtual:
+	  event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
+	  break;
+	default:
+	  event->crossing.detail = GDK_NOTIFY_UNKNOWN;
+	  break;
+	}
+
+      event->crossing.focus = xevent->xcrossing.focus;
+      event->crossing.state = xevent->xcrossing.state;
+
+      break;
+
+    case LeaveNotify:
+      GDK_NOTE (EVENTS,
+		g_message ("leave notify:\t\twindow: %ld  detail: %d subwin: %ld",
+			   xevent->xcrossing.window,
+			   xevent->xcrossing.detail, xevent->xcrossing.subwindow));
+
+      if (window_private == NULL)
+        {
+          return_val = FALSE;
+          break;
+        }
+
+      if (!set_screen_from_root (display, event, xevent->xbutton.root))
+	{
+	  return_val = FALSE;
+	  break;
+	}
+
+      /* Handle focusing (in the case where no window manager is running */
+      if (toplevel && xevent->xcrossing.detail != NotifyInferior)
+	{
+	  toplevel->has_pointer = FALSE;
+
+	  if (xevent->xcrossing.focus && !toplevel->has_focus_window)
+	    {
+	      gboolean had_focus = HAS_FOCUS (toplevel);
+
+	      toplevel->has_pointer_focus = FALSE;
+
+	      if (HAS_FOCUS (toplevel) != had_focus)
+		generate_focus_event (window, FALSE);
+	    }
+	}
+
+      event->crossing.type = GDK_LEAVE_NOTIFY;
+      event->crossing.window = window;
+
+      /* If the subwindow field of the XEvent is non-NULL, then
+       *  lookup the corresponding GdkWindow.
+       */
+      if (xevent->xcrossing.subwindow != None)
+	event->crossing.subwindow = gdk_window_lookup_for_display (display, xevent->xcrossing.subwindow);
+      else
+	event->crossing.subwindow = NULL;
+
+      event->crossing.time = xevent->xcrossing.time;
+      event->crossing.x = xevent->xcrossing.x + xoffset;
+      event->crossing.y = xevent->xcrossing.y + yoffset;
+      event->crossing.x_root = xevent->xcrossing.x_root;
+      event->crossing.y_root = xevent->xcrossing.y_root;
+
+      /* Translate the crossing mode into Gdk terms.
+       */
+      switch (xevent->xcrossing.mode)
+	{
+	case NotifyNormal:
+	  event->crossing.mode = GDK_CROSSING_NORMAL;
+	  break;
+	case NotifyGrab:
+	  event->crossing.mode = GDK_CROSSING_GRAB;
+	  break;
+	case NotifyUngrab:
+	  event->crossing.mode = GDK_CROSSING_UNGRAB;
+	  break;
+	};
+
+      /* Translate the crossing detail into Gdk terms.
+       */
+      switch (xevent->xcrossing.detail)
+	{
+	case NotifyInferior:
+	  event->crossing.detail = GDK_NOTIFY_INFERIOR;
+	  break;
+	case NotifyAncestor:
+	  event->crossing.detail = GDK_NOTIFY_ANCESTOR;
+	  break;
+	case NotifyVirtual:
+	  event->crossing.detail = GDK_NOTIFY_VIRTUAL;
+	  break;
+	case NotifyNonlinear:
+	  event->crossing.detail = GDK_NOTIFY_NONLINEAR;
+	  break;
+	case NotifyNonlinearVirtual:
+	  event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
+	  break;
+	default:
+	  event->crossing.detail = GDK_NOTIFY_UNKNOWN;
+	  break;
+	}
+
+      event->crossing.focus = xevent->xcrossing.focus;
+      event->crossing.state = xevent->xcrossing.state;
+
+      break;
+
+      /* We only care about focus events that indicate that _this_
+       * window (not a ancestor or child) got or lost the focus
+       */
+    case FocusIn:
+      GDK_NOTE (EVENTS,
+		g_message ("focus in:\t\twindow: %ld, detail: %s, mode: %s",
+			   xevent->xfocus.window,
+			   notify_details[xevent->xfocus.detail],
+			   notify_modes[xevent->xfocus.mode]));
+
+      if (toplevel)
+	{
+	  gboolean had_focus = HAS_FOCUS (toplevel);
+
+	  switch (xevent->xfocus.detail)
+	    {
+	    case NotifyAncestor:
+	    case NotifyVirtual:
+	      /* When the focus moves from an ancestor of the window to
+	       * the window or a descendent of the window, *and* the
+	       * pointer is inside the window, then we were previously
+	       * receiving keystroke events in the has_pointer_focus
+	       * case and are now receiving them in the
+	       * has_focus_window case.
+	       */
+	      if (toplevel->has_pointer &&
+		  xevent->xfocus.mode != NotifyGrab &&
+		  xevent->xfocus.mode != NotifyUngrab)
+		toplevel->has_pointer_focus = FALSE;
+
+	      /* fall through */
+	    case NotifyNonlinear:
+	    case NotifyNonlinearVirtual:
+	      if (xevent->xfocus.mode != NotifyGrab &&
+		  xevent->xfocus.mode != NotifyUngrab)
+		toplevel->has_focus_window = TRUE;
+	      /* We pretend that the focus moves to the grab
+	       * window, so we pay attention to NotifyGrab
+	       * NotifyUngrab, and ignore NotifyWhileGrabbed
+	       */
+	      if (xevent->xfocus.mode != NotifyWhileGrabbed)
+		toplevel->has_focus = TRUE;
+	      break;
+	    case NotifyPointer:
+	      /* The X server sends NotifyPointer/NotifyGrab,
+	       * but the pointer focus is ignored while a
+	       * grab is in effect
+	       */
+	      if (xevent->xfocus.mode != NotifyGrab &&
+		  xevent->xfocus.mode != NotifyUngrab)
+		toplevel->has_pointer_focus = TRUE;
+	      break;
+	    case NotifyInferior:
+	    case NotifyPointerRoot:
+	    case NotifyDetailNone:
+	      break;
+	    }
+
+	  if (HAS_FOCUS (toplevel) != had_focus)
+	    generate_focus_event (window, TRUE);
+	}
+      break;
+    case FocusOut:
+      GDK_NOTE (EVENTS,
+		g_message ("focus out:\t\twindow: %ld, detail: %s, mode: %s",
+			   xevent->xfocus.window,
+			   notify_details[xevent->xfocus.detail],
+			   notify_modes[xevent->xfocus.mode]));
+
+      if (toplevel)
+	{
+	  gboolean had_focus = HAS_FOCUS (toplevel);
+
+	  switch (xevent->xfocus.detail)
+	    {
+	    case NotifyAncestor:
+	    case NotifyVirtual:
+	      /* When the focus moves from the window or a descendent
+	       * of the window to an ancestor of the window, *and* the
+	       * pointer is inside the window, then we were previously
+	       * receiving keystroke events in the has_focus_window
+	       * case and are now receiving them in the
+	       * has_pointer_focus case.
+	       */
+	      if (toplevel->has_pointer &&
+		  xevent->xfocus.mode != NotifyGrab &&
+		  xevent->xfocus.mode != NotifyUngrab)
+		toplevel->has_pointer_focus = TRUE;
+
+	      /* fall through */
+	    case NotifyNonlinear:
+	    case NotifyNonlinearVirtual:
+	      if (xevent->xfocus.mode != NotifyGrab &&
+		  xevent->xfocus.mode != NotifyUngrab)
+		toplevel->has_focus_window = FALSE;
+	      if (xevent->xfocus.mode != NotifyWhileGrabbed)
+		toplevel->has_focus = FALSE;
+	      break;
+	    case NotifyPointer:
+	      if (xevent->xfocus.mode != NotifyGrab &&
+		  xevent->xfocus.mode != NotifyUngrab)
+		toplevel->has_pointer_focus = FALSE;
+	    break;
+	    case NotifyInferior:
+	    case NotifyPointerRoot:
+	    case NotifyDetailNone:
+	      break;
+	    }
+
+	  if (HAS_FOCUS (toplevel) != had_focus)
+	    generate_focus_event (window, FALSE);
+	}
+      break;
+
+    default:
+#ifdef HAVE_XKB
+      if (xevent->type == display_x11->xkb_event_type)
+	{
+	  XkbEvent *xkb_event = (XkbEvent *)xevent;
+
+	  switch (xkb_event->any.xkb_type)
+	    {
+	    case XkbNewKeyboardNotify:
+	    case XkbMapNotify:
+	      _gdk_keymap_keys_changed (display);
+
+	      return_val = FALSE;
+	      break;
+
+	    case XkbStateNotify:
+	      _gdk_keymap_state_changed (display, xevent);
+	      break;
+	    }
+	}
+      else
+#endif
+        return_val = FALSE;
+    }
+
+ done:
+  if (return_val)
+    {
+      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);
+    }
+  else
+    {
+      /* Mark this event as having no resources to be freed */
+      event->any.window = NULL;
+      event->any.type = GDK_NOTHING;
+    }
+
+  if (window)
+    g_object_unref (window);
+
+  return return_val;
+}
+
 static GList *
 gdk_device_manager_core_get_devices (GdkDeviceManager *device_manager,
                                      GdkDeviceType     type)



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]