]> Pileus Git - ~andy/gtk/blobdiff - gdk/x11/gdkevents-x11.c
Call the filters on the window where the event is received, not on the
[~andy/gtk] / gdk / x11 / gdkevents-x11.c
index 5706a395d8b8735eb203b83a75be4f211d9d702d..e32fe2182b29e0ed00d7a3a1e77b9078ba9fc2d2 100644 (file)
@@ -269,7 +269,7 @@ gdk_event_get_graphics_expose (GdkWindow *window)
   
   if (xevent.xany.type == GraphicsExpose)
     {
-      event = _gdk_event_new ();
+      event = gdk_event_new (GDK_NOTHING);
       
       if (gdk_event_translate (GDK_WINDOW_DISPLAY (window), event,
                               &xevent, TRUE))
@@ -315,6 +315,7 @@ gdk_event_apply_filters (XEvent *xevent,
  *
  * Adds a filter to be called when X ClientMessage events are received.
  *
+ * Since: 2.2
  **/ 
 void 
 gdk_display_add_client_message_filter (GdkDisplay   *display,
@@ -499,6 +500,185 @@ generate_focus_event (GdkWindow *window,
   gdk_event_put (&event);
 }
 
+static void
+set_screen_from_root (GdkDisplay *display,
+                     GdkEvent   *event,
+                     Window      xrootwin)
+{
+  GdkScreen *screen;
+
+  screen = _gdk_x11_display_screen_for_xrootwin (display, xrootwin);
+  g_assert (screen);
+
+  gdk_event_set_screen (event, screen);
+}
+
+static void
+translate_key_event (GdkDisplay *display,
+                    GdkEvent   *event,
+                    XEvent     *xevent)
+{
+  GdkKeymap *keymap = gdk_keymap_get_for_display (display);
+  gunichar c = 0;
+  guchar 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);
+
+  /* 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 the window this has to do with, if any, rather
+ * than the frame or root window that was selecting
+ * for substructure
+ */
+static Window
+get_real_window (XEvent *event)
+{
+  switch (event->type)
+    {      
+    case CreateNotify:
+      return event->xcreatewindow.window;
+      
+    case DestroyNotify:
+      return event->xdestroywindow.window;
+
+    case UnmapNotify:
+      return event->xunmap.window;
+
+    case MapNotify:
+      return event->xmap.window;
+
+    case MapRequest:
+      return event->xmaprequest.window;
+
+    case ReparentNotify:
+     return event->xreparent.window;
+      
+    case ConfigureNotify:
+      return event->xconfigure.window;
+      
+    case ConfigureRequest:
+      return event->xconfigurerequest.window;
+
+    case GravityNotify:
+      return event->xgravity.window;
+
+    case CirculateNotify:
+      return event->xcirculate.window;
+
+    case CirculateRequest:
+      return event->xcirculaterequest.window;
+
+    default:
+      return event->xany.window;
+    }
+}
+
+#ifdef G_ENABLE_DEBUG
+static const char notify_modes[][18] = {
+  "NotifyNormal",
+  "NotifyGrab",
+  "NotifyUngrab",
+  "NotifyWhileGrabbed"
+};
+
+static const char notify_details[][22] = {
+  "NotifyAncestor",
+  "NotifyVirtual",
+  "NotifyInferior",
+  "NotifyNonlinear",
+  "NotifyNonlinearVirtual",
+  "NotifyPointer",
+  "NotifyPointerRoot",
+  "NotifyDetailNone"
+};
+#endif
+
 static gboolean
 gdk_event_translate (GdkDisplay *display,
                     GdkEvent   *event,
@@ -508,16 +688,14 @@ gdk_event_translate (GdkDisplay *display,
   
   GdkWindow *window;
   GdkWindowObject *window_private;
+  GdkWindow *filter_window;
   GdkWindowImplX11 *window_impl = NULL;
-  static XComposeStatus compose;
-  KeySym keysym;
-  int charcount;
-  char buf[16];
   gint return_val;
   gint xoffset, yoffset;
   GdkScreen *screen = NULL;
   GdkScreenX11 *screen_x11 = NULL;
   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+  Window xwindow;
   
   return_val = FALSE;
 
@@ -556,11 +734,23 @@ gdk_event_translate (GdkDisplay *display,
        return_val = FALSE;
     }
 
-  /* Find the GdkWindow that this event occurred in. */
+  /* Find the GdkWindow that this event relates to.
+   * Basically this means substructure events
+   * are reported same as structure events
+   */
+  xwindow = get_real_window (xevent);
   
-  window = gdk_window_lookup_for_display (display, xevent->xany.window);
+  window = gdk_window_lookup_for_display (display, xwindow);
   window_private = (GdkWindowObject *) window;
 
+  /* We always run the filters for the window where the event
+   * is delivered, not the window that it relates to
+   */
+  if (xevent->xany.window == xwindow)
+    filter_window = window;
+  else
+    filter_window = gdk_window_lookup_for_display (display, xevent->xany.window);
+
   if (window)
     {
       screen = GDK_WINDOW_SCREEN (window);
@@ -577,16 +767,18 @@ gdk_event_translate (GdkDisplay *display,
       if (GDK_IS_WINDOW (window))
         {
           window_impl = GDK_WINDOW_IMPL_X11 (window_private->impl);
-         
-          if (xevent->xany.window != GDK_WINDOW_XID (window))
+
+          /* Move key events on focus window to the real toplevel, and
+           * filter out all other events on focus window
+           */          
+          if (xwindow == window_impl->focus_window)
             {
-              g_assert (xevent->xany.window == window_impl->focus_window);
-              
               switch (xevent->type)
                 {
                 case KeyPress:
                 case KeyRelease:
-                  xevent->xany.window = GDK_WINDOW_XID (window);
+                  xwindow = GDK_WINDOW_XID (window);
+                  xevent->xany.window = xwindow;
                   break;
                 default:
                   return FALSE;
@@ -608,22 +800,31 @@ gdk_event_translate (GdkDisplay *display,
          goto done;
        }
     }
-  else if (window_private)
+  else if (filter_window)
     {
       /* Apply per-window filters */
+      GdkWindowObject *filter_private = (GdkWindowObject *) filter_window;
       GdkFilterReturn result;
-      result = gdk_event_apply_filters (xevent, event,
-                                       window_private->filters);
-      
-      if (result != GDK_FILTER_CONTINUE)
+
+      if (filter_private->filters)
        {
-         return_val = (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
-         goto done;
+         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;
+           }
        }
     }
       
   if (screen_x11 && screen_x11->wmspec_check_window != None &&
-      xevent->xany.window == screen_x11->wmspec_check_window)
+      xwindow == screen_x11->wmspec_check_window)
     {
       if (xevent->type == DestroyNotify)
         {
@@ -683,48 +884,9 @@ gdk_event_translate (GdkDisplay *display,
           return_val = FALSE;
           break;
         }
-      
-      /* Lookup the string corresponding to the given keysym.
-       */
-
-      charcount = XLookupString (&xevent->xkey, buf, 16,
-                                &keysym, &compose);
-      event->key.keyval = keysym;
-      event->key.hardware_keycode = xevent->xkey.keycode;
-      
-      if (charcount > 0 && buf[charcount-1] == '\0')
-       charcount --;
-      else
-       buf[charcount] = '\0';
-      
-#ifdef G_ENABLE_DEBUG
-      if (_gdk_debug_flags & GDK_DEBUG_EVENTS)
-       {
-         g_message ("key press:\twindow: %ld  key: %12s  %d",
-                    xevent->xkey.window,
-                    event->key.keyval ? XKeysymToString (event->key.keyval) : "(none)",
-                    event->key.keyval);
-         if (charcount > 0)
-           g_message ("\t\tlength: %4d string: \"%s\"",
-                      charcount, buf);
-       }
-#endif /* G_ENABLE_DEBUG */
-
-      event->key.type = GDK_KEY_PRESS;
-      event->key.window = window;
-      event->key.time = xevent->xkey.time;
-      event->key.state = (GdkModifierType) xevent->xkey.state;
-      event->key.string = g_strdup (buf);
-      event->key.length = charcount;
-
-      /* bits 13 and 14 in the "state" field are the keyboard group */
-#define KEYBOARD_GROUP_SHIFT 13
-#define KEYBOARD_GROUP_MASK ((1 << 13) | (1 << 14))
-      
-      event->key.group = _gdk_x11_get_group_for_state (display, xevent->xkey.state);
-      
+      translate_key_event (display, event, xevent);
       break;
-      
+
     case KeyRelease:
       if (window_private == NULL)
         {
@@ -732,9 +894,6 @@ gdk_event_translate (GdkDisplay *display,
           break;
         }
       
-      /* Lookup the string corresponding to the given keysym.
-       */
-
       /* 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.
@@ -749,30 +908,13 @@ gdk_event_translate (GdkDisplay *display,
          if (next_event.type == KeyPress &&
              next_event.xkey.keycode == xevent->xkey.keycode &&
              next_event.xkey.time == xevent->xkey.time)
-           break;
+           {
+             return_val = FALSE;
+             break;
+           }
        }
-      
-      keysym = GDK_VoidSymbol;
-      charcount = XLookupString (&xevent->xkey, buf, 16,
-                                &keysym, &compose);
-      event->key.keyval = keysym;      
-      event->key.hardware_keycode = xevent->xkey.keycode;
-      
-      GDK_NOTE (EVENTS, 
-               g_message ("key release:\t\twindow: %ld  key: %12s  %d",
-                          xevent->xkey.window,
-                          XKeysymToString (event->key.keyval),
-                          event->key.keyval));
-      
-      event->key.type = GDK_KEY_RELEASE;
-      event->key.window = window;
-      event->key.time = xevent->xkey.time;
-      event->key.state = (GdkModifierType) xevent->xkey.state;
-      event->key.length = 0;
-      event->key.string = NULL;
-      
-      event->key.group = (xevent->xkey.state & KEYBOARD_GROUP_MASK) >> KEYBOARD_GROUP_SHIFT;
 
+      translate_key_event (display, event, xevent);
       break;
       
     case ButtonPress:
@@ -817,6 +959,9 @@ gdk_event_translate (GdkDisplay *display,
          event->scroll.y_root = (gfloat)xevent->xbutton.y_root;
          event->scroll.state = (GdkModifierType) xevent->xbutton.state;
          event->scroll.device = display->core_pointer;
+
+         set_screen_from_root (display, event, xevent->xbutton.root);
+         
           break;
           
         default:
@@ -832,6 +977,8 @@ gdk_event_translate (GdkDisplay *display,
          event->button.button = xevent->xbutton.button;
          event->button.device = display->core_pointer;
          
+         set_screen_from_root (display, event, xevent->xbutton.root);
+
          _gdk_event_button_generate (display, event);
           break;
        }
@@ -872,6 +1019,8 @@ gdk_event_translate (GdkDisplay *display,
       event->button.state = (GdkModifierType) xevent->xbutton.state;
       event->button.button = xevent->xbutton.button;
       event->button.device = display->core_pointer;
+
+      set_screen_from_root (display, event, xevent->xbutton.root);
       
       break;
       
@@ -902,6 +1051,8 @@ gdk_event_translate (GdkDisplay *display,
       event->motion.is_hint = xevent->xmotion.is_hint;
       event->motion.device = display->core_pointer;
       
+      set_screen_from_root (display, event, xevent->xmotion.root);
+      
       break;
       
     case EnterNotify:
@@ -921,10 +1072,10 @@ gdk_event_translate (GdkDisplay *display,
       if (window &&
          GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD &&
          xevent->xcrossing.detail != NotifyInferior &&
-         xevent->xcrossing.focus && !window_impl->has_focus)
+         xevent->xcrossing.focus && !window_impl->has_focus_window)
        {
          gboolean had_focus = HAS_FOCUS (window_impl);
-         
+
          window_impl->has_pointer_focus = TRUE;
 
          if (HAS_FOCUS (window_impl) != had_focus)
@@ -954,6 +1105,8 @@ gdk_event_translate (GdkDisplay *display,
       event->crossing.x_root = xevent->xcrossing.x_root;
       event->crossing.y_root = xevent->xcrossing.y_root;
       
+      set_screen_from_root (display, event, xevent->xcrossing.root);
+      
       /* Translate the crossing mode into Gdk terms.
        */
       switch (xevent->xcrossing.mode)
@@ -1014,12 +1167,12 @@ gdk_event_translate (GdkDisplay *display,
       if (window &&
          GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD &&
          xevent->xcrossing.detail != NotifyInferior &&
-         xevent->xcrossing.focus && !window_impl->has_focus)
+         xevent->xcrossing.focus && !window_impl->has_focus_window)
        {
          gboolean had_focus = HAS_FOCUS (window_impl);
          
          window_impl->has_pointer_focus = FALSE;
-
+         
          if (HAS_FOCUS (window_impl) != had_focus)
            generate_focus_event (window, FALSE);
        }
@@ -1041,6 +1194,8 @@ gdk_event_translate (GdkDisplay *display,
       event->crossing.x_root = xevent->xcrossing.x_root;
       event->crossing.y_root = xevent->xcrossing.y_root;
       
+      set_screen_from_root (display, event, xevent->xcrossing.root);
+      
       /* Translate the crossing mode into Gdk terms.
        */
       switch (xevent->xcrossing.mode)
@@ -1090,7 +1245,10 @@ gdk_event_translate (GdkDisplay *display,
        */
     case FocusIn:
       GDK_NOTE (EVENTS,
-               g_message ("focus in:\t\twindow: %ld", xevent->xfocus.window));
+               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 (window && GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD)
        {
@@ -1102,6 +1260,7 @@ gdk_event_translate (GdkDisplay *display,
            case NotifyNonlinear:
            case NotifyVirtual:
            case NotifyNonlinearVirtual:
+             window_impl->has_focus_window = TRUE;
              /* We pretend that the focus moves to the grab
               * window, so we pay attention to NotifyGrab
               * NotifyUngrab, and ignore NotifyWhileGrabbed
@@ -1129,8 +1288,11 @@ gdk_event_translate (GdkDisplay *display,
       break;
     case FocusOut:
       GDK_NOTE (EVENTS,
-               g_message ("focus out:\t\twindow: %ld", xevent->xfocus.window));
-
+               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 (window && GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD)
        {
          gboolean had_focus = HAS_FOCUS (window_impl);
@@ -1141,6 +1303,7 @@ gdk_event_translate (GdkDisplay *display,
            case NotifyNonlinear:
            case NotifyVirtual:
            case NotifyNonlinearVirtual:
+             window_impl->has_focus_window = FALSE;
              if (xevent->xfocus.mode != NotifyWhileGrabbed)
                window_impl->has_focus = FALSE;
              break;
@@ -1421,6 +1584,9 @@ gdk_event_translate (GdkDisplay *display,
                           : xevent->xconfigure.event != xevent->xconfigure.window
                           ? " (discarding substructure)"
                           : ""));
+      if (window && GDK_WINDOW_TYPE (window) == GDK_WINDOW_ROOT)
+       _gdk_x11_screen_size_changed (screen, xevent);
+
       if (window &&
          xevent->xconfigure.event == xevent->xconfigure.window &&
          !GDK_WINDOW_DESTROYED (window) &&
@@ -1773,9 +1939,8 @@ _gdk_events_queue (GdkDisplay *display)
            continue;
        }
       
-      event = _gdk_event_new ();
+      event = gdk_event_new (GDK_NOTHING);
       
-      event->any.type = GDK_NOTHING;
       event->any.window = NULL;
       event->any.send_event = xevent.xany.send_event ? TRUE : FALSE;
 
@@ -1860,17 +2025,19 @@ gdk_event_dispatch (GSource    *source,
 }
 
 /**
- * gdk_event_send_client_message_for_display :
- * @display : the #GdkDisplay for the window where the message is to be sent.
- * @event : the #GdkEvent to send, which should be a #GdkEventClient.
- * @winid : the window to send the X ClientMessage event to.
+ * gdk_event_send_client_message_for_display:
+ * @display: the #GdkDisplay for the window where the message is to be sent.
+ * @event: the #GdkEvent to send, which should be a #GdkEventClient.
+ * @winid: the window to send the X ClientMessage event to.
  *
  * Sends an X ClientMessage event to a given window.
  *
  * This could be used for communicating between different applications,
  * though the amount of data is limited to 20 bytes.
  *
- * Returns : non-zero on success.
+ * Returns: non-zero on success.
+ *
+ * Since: 2.2
  */
 gboolean
 gdk_event_send_client_message_for_display (GdkDisplay     *display,
@@ -1956,8 +2123,8 @@ gdk_event_send_client_message_to_all_recurse (GdkDisplay *display,
 
 /**
  * gdk_screen_broadcast_client_message:
- * @screen : the #GdkScreen where the event will be broadcasted.
- * @event : the #GdkEvent.
+ * @screen: the #GdkScreen where the event will be broadcasted.
+ * @event: the #GdkEvent.
  *
  * Sends an X ClientMessage event to all toplevel windows on @screen.
  *
@@ -1965,6 +2132,8 @@ gdk_event_send_client_message_to_all_recurse (GdkDisplay *display,
  * as described in the Inter-Client Communication Conventions Manual (ICCCM).
  * If no windows are found with the WM_STATE property set, the message is 
  * sent to all children of the root window.
+ *
+ * Since: 2.2
  */
 
 void
@@ -2126,6 +2295,18 @@ fetch_net_wm_check_window (GdkScreen *screen)
   _gdk_x11_screen_window_manager_changed (GDK_SCREEN (screen_x11));
 }
 
+/**
+ * gdk_x11_screen_get_window_manager_name:
+ * @screen: a #GdkScreen 
+ * 
+ * Returns the name of the window manager for @screen. 
+ * 
+ * Return value: the name of the window manager screen @screen, or 
+ * "unknown" if the window manager is unknown. The string is owned by GDK
+ * and should not be freed.
+ *
+ * Since: 2.2
+ **/
 const char*
 gdk_x11_screen_get_window_manager_name (GdkScreen *screen)
 {
@@ -2190,13 +2371,14 @@ struct _NetWmSupportedAtoms
 
 /**
  * gdk_x11_screen_supports_net_wm_hint:
- * @screen : the relevant #GdkScreen.
+ * @screen: the relevant #GdkScreen.
  * @property: a property atom.
  * 
  * This function is specific to the X11 backend of GDK, and indicates
  * whether the window manager supports a certain hint from the
  * Extended Window Manager Hints Specification. You can find this
- * specification on http://www.freedesktop.org.
+ * specification on 
+ * <ulink url="http://www.freedesktop.org">http://www.freedesktop.org</ulink>.
  *
  * When using this function, keep in mind that the window manager
  * can change over time; so you shouldn't use this function in
@@ -2208,6 +2390,8 @@ struct _NetWmSupportedAtoms
  * a window manager change.
  * 
  * Return value: %TRUE if the window manager supports @property
+ *
+ * Since: 2.2
  **/
 gboolean
 gdk_x11_screen_supports_net_wm_hint (GdkScreen *screen,
@@ -2390,8 +2574,10 @@ check_transform (const gchar *xsettings_name,
  * FIXME needs a list of valid settings here, or a link to 
  * more information.
  * 
- * Returns : %TRUE if the setting existed and a value was stored
+ * Returns: %TRUE if the setting existed and a value was stored
  *   in @value, %FALSE otherwise.
+ *
+ * Since: 2.2
  **/
 gboolean
 gdk_screen_get_setting (GdkScreen   *screen,