Index: mb-applet-input-manager-0.6/mbinputmgr-tray.c
===================================================================
--- mb-applet-input-manager-0.6/mbinputmgr-tray.c	(revision 1292)
+++ mb-applet-input-manager-0.6/mbinputmgr-tray.c	(working copy)
@@ -32,8 +32,20 @@
 MBInpmgrState *Inpmgr_state = NULL;
 Bool           ButtonIsDown = False;
 int            ButtonActive;
-Atom           AtomIMActivate;
 
+Atom	       atoms[2];
+char *atom_names[] =
+  {
+    "_MB_INPUT_REQUEST",
+    "_GPE_INPUT_MANAGER"
+  };
+
+#define	       _MB_INPUT_REQUEST	0
+#define	       _GPE_INPUT_MANAGER	1
+
+#define _GPE_INPUT_MANAGER_OPEN	1
+#define _GPE_INPUT_MANAGER_CLOSE 2
+
 typedef struct ButtonImgs {
   
   MBPixbufImage *active;
@@ -41,6 +53,17 @@
 
 } ButtonImgs;
 
+struct window_record
+{
+  Window w;
+  struct window_record *next;
+};
+
+struct window_record *requests;
+
+Display	 *dpy;
+Bool	 auto_enabled;
+
 void
 paint_callback ( MBTrayApp *app, Drawable drw )
 {
@@ -262,14 +285,190 @@
 }
 
 void
+really_close (void)
+{
+  if (requests == NULL && mbinputmgr_method_active (Inpmgr_state) && auto_enabled)
+    {    
+      mbinputmgr_toggle_selected_method (Inpmgr_state);
+      auto_enabled = False;
+    }
+}
+
+Bool timer_active;
+struct timeval expires;
+
+Bool
+get_timeout (struct timeval *tv)
+{
+  int sec, usec;
+  struct timeval now;
+
+  if (!timer_active)
+    return False;
+  
+  gettimeofday (&now, NULL);
+  
+  sec = expires.tv_sec - now.tv_sec;
+  usec = expires.tv_usec - now.tv_usec;
+  if (usec < 0)
+    {
+      sec--;
+      usec += 1000000;
+    }
+
+  if (sec < 0)
+    {
+      /* timer expired */
+      really_close ();
+      timer_active = False;
+      return False;
+    }
+
+  tv->tv_sec = sec;
+  tv->tv_usec = usec;
+
+  return True;
+}
+
+Bool
+process_close_request (Window w)
+{
+  struct window_record *r, *pr = NULL;
+  unsigned long tv;
+
+  for (r = requests; r != NULL && r->w != w; )
+    {
+      pr = r;
+      r = r->next;
+    }
+  
+  if (r)
+    {
+      if (pr)
+	pr->next = r->next;
+      else
+	requests = r->next;
+
+      free (r);
+      
+      if (requests == NULL && mbinputmgr_method_active (Inpmgr_state) && auto_enabled)
+	{
+	  timer_active = True;
+	  gettimeofday (&expires, NULL);
+	  expires.tv_usec += 100000;
+	  if (expires.tv_usec >= 1000000)
+	    {
+	      expires.tv_sec++;
+	      expires.tv_usec -= 1000000;
+	    }
+	}
+
+      return True;
+    }
+  
+  return False;
+}
+
+int trapped_error_code;
+int (*old_error_handler) (Display *d, XErrorEvent *e);
+
+static int
+error_handler(Display     *display,
+	      XErrorEvent *error)
+{
+   trapped_error_code = error->error_code;
+   return 0;
+}
+
+static void
+trap_errors(void)
+{
+   trapped_error_code = 0;
+   old_error_handler = XSetErrorHandler(error_handler);
+}
+
+static int
+untrap_errors(void)
+{
+   XSetErrorHandler(old_error_handler);
+   return trapped_error_code;
+}
+
+Bool
+process_open_request (Window w)
+{
+  struct window_record *r;
+
+  for (r = requests; r != NULL && r->w != w; r = r->next)
+    ;
+
+  if (r)
+    return True;
+
+  trap_errors ();
+  XSelectInput (dpy, w, StructureNotifyMask);
+  XSync (dpy, False);
+  if (untrap_errors ())
+    return False;
+
+  r = malloc (sizeof (*r));
+  r->next = requests;
+  r->w = w;
+  requests = r;
+
+  if (!mbinputmgr_method_active(Inpmgr_state))
+    {
+      mbinputmgr_toggle_selected_method (Inpmgr_state);
+      auto_enabled = True;
+    }
+
+  return False;
+}
+
+Bool docked_already;
+
+void
+is_docked (void)
+{
+  Window	 tray_w;
+
+  tray_w = mb_tray_app_xwin (app);
+
+  if (XGetSelectionOwner (dpy, atoms[_GPE_INPUT_MANAGER]) == None)
+    {
+      XSetSelectionOwner (dpy, atoms[_GPE_INPUT_MANAGER], tray_w, CurrentTime);
+    } 
+  else 
+    {
+      fprintf (stderr, "Unable to claim _GPE_INPUT_MANAGER selection.\n");
+    }
+}
+
+void
 xevent_callback (MBTrayApp *app, XEvent *ev)
 {
   if (ev->type == ClientMessage)
     {
       XClientMessageEvent *cmev = (XClientMessageEvent *)&ev->xconfigure;
 
-      if (cmev->message_type == AtomIMActivate)
+      if (cmev->message_type == atoms[_GPE_INPUT_MANAGER])
 	{
+	  switch (cmev->data.l[0])
+	    {
+	    case _GPE_INPUT_MANAGER_OPEN:
+	      process_open_request (cmev->data.l[1]);
+	      break;
+	    case _GPE_INPUT_MANAGER_CLOSE:
+	      process_close_request (cmev->data.l[1]);
+	      break;
+	    default:
+	      fprintf (stderr, "received unknown _GPE_INPUT_MANAGER request %d\n", cmev->data.l[0]);
+	      break;
+	    }
+	} 
+#ifndef DISABLE_OLD_PROTOCOL
+      else if (cmev->message_type == atoms[_MB_INPUT_REQUEST])
+	{
 	  /* De Activate */
 	  if (cmev->data.l[0] == 0 && mbinputmgr_method_active(Inpmgr_state))
 	    mbinputmgr_toggle_selected_method (Inpmgr_state);
@@ -278,8 +477,20 @@
 		   && !mbinputmgr_method_active(Inpmgr_state))
 	    mbinputmgr_toggle_selected_method (Inpmgr_state);
 	}
+#endif
     }
+  else if (ev->type == UnmapNotify)
+    {
+      XUnmapEvent *uev = &ev->xunmap;
 
+      process_close_request (uev->window);
+    }
+  else if (ev->type == ConfigureNotify && !docked_already)
+    {
+      docked_already = TRUE;
+      is_docked ();
+    }
+
   mb_menu_handle_xevent (PopupMenu, ev);
 }
 
@@ -347,11 +558,42 @@
   free(icon_path);
 }
 
+static Bool
+get_xevent_timed(Display* dpy, XEvent* event_return, struct timeval *tv)
+{
+  if (tv == NULL) 
+    {
+      XNextEvent(dpy, event_return);
+      return True;
+    }
+
+  XFlush(dpy);
+
+  if (XPending(dpy) == 0) 
+    {
+      int fd = ConnectionNumber(dpy);
+      fd_set readset;
+      FD_ZERO(&readset);
+      FD_SET(fd, &readset);
+      if (select(fd+1, &readset, NULL, NULL, tv) == 0) 
+	{
+	  return False;
+	} else {
+	  XNextEvent(dpy, event_return);
+	  return True;
+	}
+    } else {
+      XNextEvent(dpy, event_return);
+      return True;
+    }
+}
+
 int 
 main(int argc, char **argv)
 {
   int            i;
   MBPixbufImage *app_icon_img  = NULL;
+  XEvent xevent;
 
   app = mb_tray_app_new ( "Input Selector",
 			  resize_callback,
@@ -359,13 +601,13 @@
 			  &argc,
 			  &argv );  
 
+  dpy = mb_tray_app_xdisplay (app);
+
   Pixbuf = mb_pixbuf_new(mb_tray_app_xdisplay(app), 
 			 mb_tray_app_xscreen(app));
 
-  AtomIMActivate = XInternAtom(mb_tray_app_xdisplay(app), 
-			       "_MB_INPUT_REQUEST", False);
+  XInternAtoms (dpy, atom_names, sizeof (atom_names) / sizeof (atom_names[0]), False, atoms);
 
-
   PopupMenu = mb_menu_new (mb_tray_app_xdisplay(app),
 			   mb_tray_app_xscreen(app));
 
@@ -399,17 +641,30 @@
 
   mb_tray_app_set_xevent_callback (app, xevent_callback );
 
+  mb_tray_app_set_xevent_mask (app, SubstructureNotifyMask);
+
   mb_tray_app_set_button_callback (app, button_callback );
 
   /* XXX set up dnotify to reload entrys only on _addition_  */
 
+#ifndef DISABLE_OLD_PROTOCOL
   XSelectInput(mb_tray_app_xdisplay(app),
 	       mb_tray_app_xrootwin(app),
 	       SubstructureNotifyMask);
+#endif 
 
+  /* Not using mb_tray_app_main() to avoid libmb's broken get_xevent_timed() */
+  mb_tray_app_main_init (app);
+  for (;;)
+    {
+      struct timeval tv, *tvp = NULL;
 
-  mb_tray_app_main (app);
+      if (get_timeout (&tv))
+	tvp = &tv;
 
+      if (get_xevent_timed (dpy, &xevent, tvp))
+	mb_tray_handle_xevent (app, &xevent);
+    }
+
   return 0;
 }
-