]> Pileus Git - ~andy/gtk/blobdiff - gdk/x11/gdkevents-x11.c
Separate out tracking of the X server focus window from tracking our idea
[~andy/gtk] / gdk / x11 / gdkevents-x11.c
index e8bedf9e366b5d44fd0c2303e2744c5f2d4e377c..f0e44e8b06db4f6b55209a2560d4c3148a67bc06 100644 (file)
@@ -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,
@@ -512,6 +513,105 @@ set_screen_from_root (GdkDisplay *display,
   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
@@ -559,6 +659,26 @@ get_real_window (XEvent *event)
     }
 }
 
+#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,
@@ -569,10 +689,6 @@ gdk_event_translate (GdkDisplay *display,
   GdkWindow *window;
   GdkWindowObject *window_private;
   GdkWindowImplX11 *window_impl = NULL;
-  static XComposeStatus compose;
-  KeySym keysym;
-  int charcount;
-  char buf[16];
   gint return_val;
   gint xoffset, yoffset;
   GdkScreen *screen = NULL;
@@ -750,48 +866,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)
         {
@@ -799,9 +876,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.
@@ -816,30 +890,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:
@@ -997,10 +1054,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)
@@ -1092,12 +1149,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);
        }
@@ -1170,7 +1227,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)
        {
@@ -1182,6 +1242,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
@@ -1209,8 +1270,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);
@@ -1221,6 +1285,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;
@@ -1942,17 +2007,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,
@@ -2038,8 +2105,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.
  *
@@ -2047,6 +2114,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
@@ -2208,6 +2277,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)
 {
@@ -2272,13 +2353,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
@@ -2290,6 +2372,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,
@@ -2472,8 +2556,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,