]> Pileus Git - ~andy/gtk/blobdiff - modules/input/gtkimcontextxim.c
Merge remote-tracking branch 'origin/master' into gdk-backend-wayland
[~andy/gtk] / modules / input / gtkimcontextxim.c
index 54a6482cce229448a44e7864490a518501e5b77c..a6adf9f2808a733f1993a989c7b4b70a804de02d 100644 (file)
  * Boston, MA 02111-1307, USA.
  */
 
+#include "config.h"
 #include "locale.h"
 #include <string.h>
+#include <stdlib.h>
 
-#include "gtk/gtkintl.h"
-#include "gtk/gtklabel.h"
-#include "gtk/gtksignal.h"
-#include "gtk/gtkwindow.h"
 #include "gtkimcontextxim.h"
 
+#include "gtk/gtkintl.h"
+
 typedef struct _StatusWindow StatusWindow;
 typedef struct _GtkXIMInfo GtkXIMInfo;
 
@@ -62,6 +62,8 @@ struct _GtkIMContextXIM
   XIMCallback status_done_callback;
   XIMCallback status_draw_callback;
 
+  XIMCallback string_conversion_callback;
+
   XIC ic;
 
   guint filter_key_release : 1;
@@ -82,10 +84,12 @@ struct _GtkXIMInfo
   GtkSettings *settings;
   gulong status_set;
   gulong preedit_set;
+  gulong display_closed_cb;
   XIMStyles *xim_styles;
   GSList *ics;
 
   guint reconnecting :1;
+  guint supports_string_conversion;
 };
 
 /* A context status window; these are kept in the status_windows list. */
@@ -138,11 +142,15 @@ static void xim_destroy_callback   (XIM      xim,
                                    XPointer call_data);
 
 static XIC       gtk_im_context_xim_get_ic            (GtkIMContextXIM *context_xim);
+static void           xim_info_display_closed (GdkDisplay *display,
+                                              gboolean    is_error,
+                                              GtkXIMInfo *info);
+
 static GObjectClass *parent_class;
 
 GType gtk_type_im_context_xim = 0;
 
-GSList *open_ims = NULL;
+static GSList *open_ims = NULL;
 
 /* List of status windows for different toplevels */
 static GSList *status_windows = NULL;
@@ -150,7 +158,7 @@ static GSList *status_windows = NULL;
 void
 gtk_im_context_xim_register_type (GTypeModule *type_module)
 {
-  static const GTypeInfo im_context_xim_info =
+  const GTypeInfo im_context_xim_info =
   {
     sizeof (GtkIMContextXIMClass),
     (GBaseInitFunc) NULL,
@@ -302,6 +310,7 @@ setup_im (GtkXIMInfo *info)
 {
   XIMValuesList *ic_values = NULL;
   XIMCallback im_destroy_callback;
+  GdkDisplay *display;
 
   if (info->im == NULL)
     return;
@@ -318,25 +327,6 @@ setup_im (GtkXIMInfo *info)
                NULL);
 
   info->settings = gtk_settings_get_for_screen (info->screen);
-
-  if (!g_object_class_find_property (G_OBJECT_GET_CLASS (info->settings),
-                                    "gtk-im-preedit-style"))
-    gtk_settings_install_property (g_param_spec_enum ("gtk-im-preedit-style",
-                                                     P_("IM Preedit style"),
-                                                     P_("How to draw the input method preedit string"),
-                                                     GTK_TYPE_IM_PREEDIT_STYLE,
-                                                     GTK_IM_PREEDIT_CALLBACK,
-                                                     G_PARAM_READWRITE));
-
-  if (!g_object_class_find_property (G_OBJECT_GET_CLASS (info->settings),
-                                    "gtk-im-status-style"))
-    gtk_settings_install_property (g_param_spec_enum ("gtk-im-status-style",
-                                                     P_("IM Status style"),
-                                                     P_("How to draw the input method statusbar"),
-                                                     GTK_TYPE_IM_STATUS_STYLE,
-                                                     GTK_IM_STATUS_CALLBACK,
-                                                     G_PARAM_READWRITE));
-
   info->status_set = g_signal_connect_swapped (info->settings,
                                               "notify::gtk-im-status-style",
                                               G_CALLBACK (status_style_change),
@@ -346,21 +336,35 @@ setup_im (GtkXIMInfo *info)
                                                G_CALLBACK (preedit_style_change),
                                                info);
 
-  status_style_change (info);
-  preedit_style_change (info);
-
-#if 0
+  info->supports_string_conversion = FALSE;
   if (ic_values)
     {
+      int i;
+      
+      for (i = 0; i < ic_values->count_values; i++)
+       if (strcmp (ic_values->supported_values[i],
+                   XNStringConversionCallback) == 0)
+         {
+           info->supports_string_conversion = TRUE;
+           break;
+         }
+
+#if 0
       for (i = 0; i < ic_values->count_values; i++)
        g_print ("%s\n", ic_values->supported_values[i]);
       for (i = 0; i < xim_styles->count_styles; i++)
        g_print ("%#x\n", xim_styles->supported_styles[i]);
-    }
 #endif
+      
+      XFree (ic_values);
+    }
 
-  if (ic_values)
-    XFree (ic_values);
+  status_style_change (info);
+  preedit_style_change (info);
+
+  display = gdk_screen_get_display (info->screen);
+  info->display_closed_cb = g_signal_connect (display, "closed",
+                                             G_CALLBACK (xim_info_display_closed), info);
 }
 
 static void
@@ -379,12 +383,16 @@ xim_info_display_closed (GdkDisplay *display,
     set_ic_client_window (tmp_list->data, NULL);
 
   g_slist_free (ics);
-  
-  g_signal_handler_disconnect (info->settings, info->status_set);
-  g_signal_handler_disconnect (info->settings, info->preedit_set);
-  
-  XFree (info->xim_styles->supported_styles);
-  XFree (info->xim_styles);
+
+  if (info->status_set)
+    g_signal_handler_disconnect (info->settings, info->status_set);
+  if (info->preedit_set)
+    g_signal_handler_disconnect (info->settings, info->preedit_set);
+  if (info->display_closed_cb)
+    g_signal_handler_disconnect (display, info->display_closed_cb);
+
+  if (info->xim_styles)
+    XFree (info->xim_styles);
   g_free (info->locale);
 
   if (info->im)
@@ -440,9 +448,6 @@ xim_info_try_im (GtkXIMInfo *info)
          return;
        }
       setup_im (info);
-
-      g_signal_connect (display, "closed",
-                       G_CALLBACK (xim_info_display_closed), info);
     }
 }
 
@@ -456,7 +461,9 @@ xim_destroy_callback (XIM      xim,
   info->im = NULL;
 
   g_signal_handler_disconnect (info->settings, info->status_set);
+  info->status_set = 0;
   g_signal_handler_disconnect (info->settings, info->preedit_set);
+  info->preedit_set = 0;
 
   reinitialize_all_ics (info);
   xim_info_try_im (info);
@@ -469,7 +476,7 @@ get_im (GdkWindow *client_window,
 {
   GSList *tmp_list;
   GtkXIMInfo *info;
-  GdkScreen *screen = gdk_drawable_get_screen (client_window);
+  GdkScreen *screen = gdk_window_get_screen (client_window);
 
   info = NULL;
   tmp_list = open_ims;
@@ -505,6 +512,7 @@ get_im (GdkWindow *client_window,
       info->settings = NULL;
       info->preedit_set = 0;
       info->status_set = 0;
+      info->display_closed_cb = 0;
       info->ics = NULL;
       info->reconnecting = FALSE;
       info->im = NULL;
@@ -550,6 +558,30 @@ gtk_im_context_xim_finalize (GObject *obj)
 
   context_xim->finalizing = TRUE;
 
+  if (context_xim->im_info && !context_xim->im_info->ics->next) 
+    {
+      if (context_xim->im_info->reconnecting)
+       {
+         GdkDisplay *display;
+
+         display = gdk_screen_get_display (context_xim->im_info->screen);
+         XUnregisterIMInstantiateCallback (GDK_DISPLAY_XDISPLAY (display),
+                                           NULL, NULL, NULL,
+                                           xim_instantiate_callback,
+                                           (XPointer)context_xim->im_info);
+       }
+      else if (context_xim->im_info->im)
+       {
+         XIMCallback im_destroy_callback;
+
+         im_destroy_callback.client_data = NULL;
+         im_destroy_callback.callback = NULL;
+         XSetIMValues (context_xim->im_info->im,
+                       XNDestroyCallback, &im_destroy_callback,
+                       NULL);
+       }
+    }
+
   set_ic_client_window (context_xim, NULL);
 
   g_free (context_xim->locale);
@@ -571,7 +603,7 @@ reinitialize_ic (GtkIMContextXIM *context_xim)
        {
          context_xim->preedit_length = 0;
          if (!context_xim->finalizing)
-           g_signal_emit_by_name (context_xim, "preedit_changed");
+           g_signal_emit_by_name (context_xim, "preedit-changed");
        }
     }
   /* 
@@ -618,7 +650,7 @@ gtk_im_context_xim_new (void)
   GtkIMContextXIM *result;
   const gchar *charset;
 
-  result = GTK_IM_CONTEXT_XIM (g_object_new (GTK_TYPE_IM_CONTEXT_XIM, NULL));
+  result = g_object_new (GTK_TYPE_IM_CONTEXT_XIM, NULL);
 
   result->locale = g_strdup (setlocale (LC_CTYPE, NULL));
   
@@ -665,7 +697,7 @@ gtk_im_context_xim_filter_keypress (GtkIMContext *context,
   KeySym keysym;
   Status status;
   gboolean result = FALSE;
-  GdkWindow *root_window = gdk_screen_get_root_window (gdk_drawable_get_screen (event->window));
+  GdkWindow *root_window = gdk_screen_get_root_window (gdk_window_get_screen (event->window));
 
   XKeyPressedEvent xevent;
 
@@ -675,9 +707,9 @@ gtk_im_context_xim_filter_keypress (GtkIMContext *context,
   xevent.type = (event->type == GDK_KEY_PRESS) ? KeyPress : KeyRelease;
   xevent.serial = 0;           /* hope it doesn't matter */
   xevent.send_event = event->send_event;
-  xevent.display = GDK_DRAWABLE_XDISPLAY (event->window);
-  xevent.window = GDK_DRAWABLE_XID (event->window);
-  xevent.root = GDK_DRAWABLE_XID (root_window);
+  xevent.display = GDK_WINDOW_XDISPLAY (event->window);
+  xevent.window = GDK_WINDOW_XID (event->window);
+  xevent.root = GDK_WINDOW_XID (root_window);
   xevent.subwindow = xevent.window;
   xevent.time = event->time;
   xevent.x = xevent.x_root = 0;
@@ -686,9 +718,13 @@ gtk_im_context_xim_filter_keypress (GtkIMContext *context,
   xevent.keycode = event->hardware_keycode;
   xevent.same_screen = True;
   
-  if (XFilterEvent ((XEvent *)&xevent, GDK_DRAWABLE_XID (context_xim->client_window)))
+  if (XFilterEvent ((XEvent *)&xevent, GDK_WINDOW_XID (context_xim->client_window)))
     return TRUE;
   
+  if (event->state &
+      (gtk_accelerator_get_default_mod_mask () & ~(GDK_SHIFT_MASK | GDK_CONTROL_MASK))) 
+    return FALSE;
+
  again:
   if (ic)
     num_bytes = XmbLookupString (ic, &xevent, buffer, buffer_size, &keysym, &status);
@@ -791,11 +827,11 @@ gtk_im_context_xim_set_cursor_location (GtkIMContext *context,
     return;
 
   spot.x = area->x;
-  spot.y = area->y;
+  spot.y = area->y + area->height;
 
   preedit_attr = XVaCreateNestedList (0,
                                      XNSpotLocation, &spot,
-                                     0);
+                                     NULL);
   XSetICValues (ic,
                XNPreeditAttributes, preedit_attr,
                NULL);
@@ -842,7 +878,7 @@ gtk_im_context_xim_reset (GtkIMContext *context)
 
   preedit_attr = XVaCreateNestedList(0,
                                      XNPreeditState, &preedit_state,
-                                     0);
+                                     NULL);
   if (!XGetICValues(ic,
                     XNPreeditAttributes, preedit_attr,
                     NULL))
@@ -854,7 +890,7 @@ gtk_im_context_xim_reset (GtkIMContext *context)
 
   preedit_attr = XVaCreateNestedList(0,
                                      XNPreeditState, preedit_state,
-                                     0);
+                                     NULL);
   if (have_preedit_state)
     XSetICValues(ic,
                 XNPreeditAttributes, preedit_attr,
@@ -875,7 +911,7 @@ gtk_im_context_xim_reset (GtkIMContext *context)
   if (context_xim->preedit_length)
     {
       context_xim->preedit_length = 0;
-      g_signal_emit_by_name (context, "preedit_changed");
+      g_signal_emit_by_name (context, "preedit-changed");
     }
 
   XFree (result);
@@ -977,7 +1013,7 @@ preedit_start_callback (XIC      xic,
   GtkIMContextXIM *context_xim = GTK_IM_CONTEXT_XIM (context);
   
   if (!context_xim->finalizing)
-    g_signal_emit_by_name (context, "preedit_start");
+    g_signal_emit_by_name (context, "preedit-start");
 
   return -1;                   /* No length limit */
 }                   
@@ -990,8 +1026,15 @@ preedit_done_callback (XIC      xic,
   GtkIMContext *context = GTK_IM_CONTEXT (client_data);
   GtkIMContextXIM *context_xim = GTK_IM_CONTEXT_XIM (context);
 
+  if (context_xim->preedit_length)
+    {
+      context_xim->preedit_length = 0;
+      if (!context_xim->finalizing)
+       g_signal_emit_by_name (context_xim, "preedit-changed");
+    }
+
   if (!context_xim->finalizing)
-    g_signal_emit_by_name (context, "preedit_end");  
+    g_signal_emit_by_name (context, "preedit-end");
 }                   
 
 static gint
@@ -1113,11 +1156,10 @@ preedit_draw_callback (XIC                           xic,
 
   context->preedit_length += diff;
 
-  if (new_text)
-    g_free (new_text);
+  g_free (new_text);
 
   if (!context->finalizing)
-    g_signal_emit_by_name (context, "preedit_changed");
+    g_signal_emit_by_name (context, "preedit-changed");
 }
     
 
@@ -1132,7 +1174,7 @@ preedit_caret_callback (XIC                            xic,
     {
       context->preedit_cursor = call_data->position;
       if (!context->finalizing)
-       g_signal_emit_by_name (context, "preedit_changed");
+       g_signal_emit_by_name (context, "preedit-changed");
     }
   else
     {
@@ -1178,6 +1220,120 @@ status_draw_callback (XIC      xic,
     }
 }
 
+static void
+string_conversion_callback (XIC xic, XPointer client_data, XPointer call_data)
+{
+  GtkIMContextXIM *context_xim;
+  XIMStringConversionCallbackStruct *conv_data;
+  gchar *surrounding;
+  gint  cursor_index;
+
+  context_xim = (GtkIMContextXIM *)client_data;
+  conv_data = (XIMStringConversionCallbackStruct *)call_data;
+
+  if (gtk_im_context_get_surrounding ((GtkIMContext *)context_xim,
+                                      &surrounding, &cursor_index))
+    {
+      gchar *text = NULL;
+      gsize text_len = 0;
+      gint  subst_offset = 0, subst_nchars = 0;
+      gint  i;
+      gchar *p = surrounding + cursor_index, *q;
+      gshort position = (gshort)conv_data->position;
+
+      if (position > 0)
+        {
+          for (i = position; i > 0 && *p; --i)
+            p = g_utf8_next_char (p);
+          if (i > 0)
+            return;
+        }
+      /* According to X11R6.4 Xlib - C Library Reference Manual
+       * section 13.5.7.3 String Conversion Callback,
+       * XIMStringConversionPosition is starting position _relative_
+       * to current client's cursor position. So it should be able
+       * to be negative, or referring to a position before the cursor
+       * would be impossible. But current X protocol defines this as
+       * unsigned short. So, compiler may warn about the value range
+       * here. We hope the X protocol is fixed soon.
+       */
+      else if (position < 0)
+        {
+          for (i = position; i < 0 && p > surrounding; ++i)
+            p = g_utf8_prev_char (p);
+          if (i < 0)
+            return;
+        }
+
+      switch (conv_data->direction)
+        {
+        case XIMForwardChar:
+          for (i = conv_data->factor, q = p; i > 0 && *q; --i)
+            q = g_utf8_next_char (q);
+          if (i > 0)
+            break;
+          text = g_locale_from_utf8 (p, q - p, NULL, &text_len, NULL);
+          subst_offset = position;
+          subst_nchars = conv_data->factor;
+          break;
+
+        case XIMBackwardChar:
+          for (i = conv_data->factor, q = p; i > 0 && q > surrounding; --i)
+            q = g_utf8_prev_char (q);
+          if (i > 0)
+            break;
+          text = g_locale_from_utf8 (q, p - q, NULL, &text_len, NULL);
+          subst_offset = position - conv_data->factor;
+          subst_nchars = conv_data->factor;
+          break;
+
+        case XIMForwardWord:
+        case XIMBackwardWord:
+        case XIMCaretUp:
+        case XIMCaretDown:
+        case XIMNextLine:
+        case XIMPreviousLine:
+        case XIMLineStart:
+        case XIMLineEnd:
+        case XIMAbsolutePosition:
+        case XIMDontChange:
+        default:
+          break;
+        }
+      /* block out any failure happenning to "text", including conversion */
+      if (text)
+        {
+          conv_data->text = (XIMStringConversionText *)
+                              malloc (sizeof (XIMStringConversionText));
+          if (conv_data->text)
+            {
+              conv_data->text->length = text_len;
+              conv_data->text->feedback = NULL;
+              conv_data->text->encoding_is_wchar = False;
+              conv_data->text->string.mbs = (char *)malloc (text_len);
+              if (conv_data->text->string.mbs)
+                memcpy (conv_data->text->string.mbs, text, text_len);
+              else
+                {
+                  free (conv_data->text);
+                  conv_data->text = NULL;
+                }
+            }
+
+          g_free (text);
+        }
+      if (conv_data->operation == XIMStringConversionSubstitution
+          && subst_nchars > 0)
+        {
+          gtk_im_context_delete_surrounding ((GtkIMContext *)context_xim,
+                                            subst_offset, subst_nchars);
+        }
+
+      g_free (surrounding);
+    }
+}
+
+
 static XVaNestedList
 set_preedit_callback (GtkIMContextXIM *context_xim)
 {
@@ -1215,6 +1371,21 @@ set_status_callback (GtkIMContextXIM *context_xim)
 }
 
 
+static void
+set_string_conversion_callback (GtkIMContextXIM *context_xim, XIC xic)
+{
+  if (!context_xim->im_info->supports_string_conversion)
+    return;
+  
+  context_xim->string_conversion_callback.client_data = (XPointer)context_xim;
+  context_xim->string_conversion_callback.callback = (XIMProc)string_conversion_callback;
+  
+  XSetICValues (xic,
+               XNStringConversionCallback,
+               (XPointer)&context_xim->string_conversion_callback,
+               NULL);
+}
+
 static XIC
 gtk_im_context_xim_get_ic (GtkIMContextXIM *context_xim)
 {
@@ -1228,7 +1399,7 @@ gtk_im_context_xim_get_ic (GtkIMContextXIM *context_xim)
       const char *name2 = NULL;
       XVaNestedList list2 = NULL;
       XIMStyle im_style = 0;
-      XIC xic = 0;
+      XIC xic = NULL;
 
       if (context_xim->use_preedit &&
          (context_xim->im_info->style & PREEDIT_MASK) == XIMPreeditCallbacks)
@@ -1263,7 +1434,7 @@ gtk_im_context_xim_get_ic (GtkIMContextXIM *context_xim)
 
       xic = XCreateIC (context_xim->im_info->im,
                       XNInputStyle, im_style,
-                      XNClientWindow, GDK_DRAWABLE_XID (context_xim->client_window),
+                      XNClientWindow, GDK_WINDOW_XID (context_xim->client_window),
                       name1, list1,
                       name2, list2,
                       NULL);
@@ -1285,6 +1456,7 @@ gtk_im_context_xim_get_ic (GtkIMContextXIM *context_xim)
                        XNFilterEvents, &mask,
                        NULL);
          context_xim->filter_key_release = (mask & KeyReleaseMask) != 0;
+         set_string_conversion_callback (context_xim, xic);
        }
       
       context_xim->ic = xic;
@@ -1356,7 +1528,7 @@ claim_status_window (GtkIMContextXIM *context_xim)
   if (!context_xim->status_window && context_xim->client_widget)
     {
       GtkWidget *toplevel = gtk_widget_get_toplevel (context_xim->client_widget);
-      if (toplevel && GTK_WIDGET_TOPLEVEL (toplevel))
+      if (toplevel && gtk_widget_is_toplevel (toplevel))
        {
          StatusWindow *status_window = status_window_get (toplevel);
 
@@ -1390,7 +1562,7 @@ update_in_toplevel (GtkIMContextXIM *context_xim)
     {
       GtkWidget *toplevel = gtk_widget_get_toplevel (context_xim->client_widget);
       
-      context_xim->in_toplevel = (toplevel && GTK_WIDGET_TOPLEVEL (toplevel));
+      context_xim->in_toplevel = (toplevel && gtk_widget_is_toplevel (toplevel));
     }
   else
     context_xim->in_toplevel = FALSE;
@@ -1501,10 +1673,12 @@ on_status_toplevel_configure (GtkWidget         *toplevel,
   if (status_window->window)
     {
       height = gdk_screen_get_height (gtk_widget_get_screen (toplevel));
-  
-      gdk_window_get_frame_extents (toplevel->window, &rect);
-      gtk_widget_size_request (status_window->window, &requisition);
-      
+
+      gdk_window_get_frame_extents (gtk_widget_get_window (toplevel),
+                                    &rect);
+      gtk_widget_get_preferred_size ( (status_window->window),
+                                 &requisition, NULL);
+
       if (rect.y + rect.height + requisition.height < height)
        y = rect.y + rect.height;
       else
@@ -1563,7 +1737,7 @@ status_window_get (GtkWidget *toplevel)
   g_signal_connect (toplevel, "destroy",
                    G_CALLBACK (on_status_toplevel_destroy),
                    status_window);
-  g_signal_connect (toplevel, "configure_event",
+  g_signal_connect (toplevel, "configure-event",
                    G_CALLBACK (on_status_toplevel_configure),
                    status_window);
   g_signal_connect (toplevel, "notify::screen",
@@ -1578,38 +1752,29 @@ status_window_get (GtkWidget *toplevel)
 /* Draw the background (normally white) and border for the status window
  */
 static gboolean
-on_status_window_expose_event (GtkWidget      *widget,
-                              GdkEventExpose *event)
+on_status_window_draw (GtkWidget *widget,
+                       cairo_t   *cr)
 {
-  gdk_draw_rectangle (widget->window,
-                     widget->style->base_gc [GTK_STATE_NORMAL],
-                     TRUE,
-                     0, 0,
-                     widget->allocation.width, widget->allocation.height);
-  gdk_draw_rectangle (widget->window,
-                     widget->style->text_gc [GTK_STATE_NORMAL],
-                     FALSE,
-                     0, 0,
-                     widget->allocation.width - 1, widget->allocation.height - 1);
+  GtkStyleContext *style;
+  GdkRGBA color;
 
-  return FALSE;
-}
+  style = gtk_widget_get_style_context (widget);
 
-/* We watch the ::style-set signal for our label widget
- * and use that to change it's foreground color to match
- * the 'text' color of the toplevel window. The text/base
- * pair of colors might be reversed from the fg/bg pair
- * that are normally used for labels.
- */
-static void
-on_status_window_style_set (GtkWidget *toplevel,
-                           GtkStyle  *previous_style,
-                           GtkWidget *label)
-{
-  gint i;
-  
-  for (i = 0; i < 5; i++)
-    gtk_widget_modify_fg (label, i, &toplevel->style->text[i]);
+  gtk_style_context_get_background_color (style, 0, &color);
+  gdk_cairo_set_source_rgba (cr, &color);
+  cairo_paint (cr);
+
+  gtk_style_context_get_color (style, 0, &color);
+  gdk_cairo_set_source_rgba (cr, &color);
+  cairo_paint (cr);
+
+  cairo_rectangle (cr, 
+                   0, 0,
+                   gtk_widget_get_allocated_width (widget) - 1,
+                   gtk_widget_get_allocated_height (widget) - 1);
+  cairo_fill (cr);
+
+  return FALSE;
 }
 
 /* Creates the widgets for the status window; called when we
@@ -1631,12 +1796,10 @@ status_window_make_window (StatusWindow *status_window)
   gtk_misc_set_padding (GTK_MISC (status_label), 1, 1);
   gtk_widget_show (status_label);
   
-  g_signal_connect (window, "style_set",
-                   G_CALLBACK (on_status_window_style_set), status_label);
   gtk_container_add (GTK_CONTAINER (window), status_label);
   
-  g_signal_connect (window, "expose_event",
-                   G_CALLBACK (on_status_window_expose_event), NULL);
+  g_signal_connect (window, "draw",
+                   G_CALLBACK (on_status_window_draw), NULL);
   
   gtk_window_set_screen (GTK_WINDOW (status_window->window),
                         gtk_widget_get_screen (status_window->toplevel));
@@ -1658,7 +1821,7 @@ status_window_set_text (StatusWindow *status_window,
       if (!status_window->window)
        status_window_make_window (status_window);
       
-      label = GTK_BIN (status_window->window)->child;
+      label = gtk_bin_get_child (GTK_BIN (status_window->window));
       gtk_label_set_text (GTK_LABEL (label), text);
   
       gtk_widget_show (status_window->window);
@@ -1681,4 +1844,13 @@ gtk_im_context_xim_shutdown (void)
 {
   while (status_windows)
     status_window_free (status_windows->data);
+
+  while (open_ims)
+    {
+      GtkXIMInfo *info = open_ims->data;
+      GdkDisplay *display = gdk_screen_get_display (info->screen);
+
+      xim_info_display_closed (display, FALSE, info);
+      open_ims = g_slist_remove_link (open_ims, open_ims);
+    }
 }