static GdkFilterReturn
na_tray_manager_window_filter (GdkXEvent *xev,
                               GdkEvent  *event,
                               gpointer   data)
{
  XEvent        *xevent = (GdkXEvent *)xev;
  NaTrayManager *manager = data;

  if (xevent->type == ClientMessage)
    {
      /* We handle this client message here. See comment in
       * na_tray_manager_handle_client_message_opcode() for details */
      if (xevent->xclient.message_type == manager->opcode_atom &&
          xevent->xclient.data.l[1]    == SYSTEM_TRAY_REQUEST_DOCK)
	{
          na_tray_manager_handle_dock_request (manager,
                                               (XClientMessageEvent *) xevent);
          return GDK_FILTER_REMOVE;
	}
    }
  else if (xevent->type == SelectionClear)
    {
      g_signal_emit (manager, manager_signals[LOST_SELECTION], 0);
      na_tray_manager_unmanage (manager);
    }

  return GDK_FILTER_CONTINUE;
}
//FIXME investigate why this doesn't work
static gboolean
na_tray_manager_selection_clear_event (GtkWidget         *widget,
                                       GdkEventSelection *event,
                                       NaTrayManager     *manager)
{
  g_signal_emit (manager, manager_signals[LOST_SELECTION], 0);
  na_tray_manager_unmanage (manager);

  return FALSE;
}
static void
na_tray_manager_finalize (GObject *object)
{
  NaTrayManager *manager;
  
  manager = NA_TRAY_MANAGER (object);

  na_tray_manager_unmanage (manager);

  g_list_free (manager->messages);
  g_hash_table_destroy (manager->socket_table);
  
  G_OBJECT_CLASS (na_tray_manager_parent_class)->finalize (object);
}
static GdkFilterReturn
na_tray_manager_window_filter (GdkXEvent *xev,
                               GdkEvent  *event,
                               gpointer   data)
{
  XEvent        *xevent = (GdkXEvent *)xev;
  NaTrayManager *manager = data;

  if (xevent->type == ClientMessage)
    {
      /* _NET_SYSTEM_TRAY_OPCODE: SYSTEM_TRAY_REQUEST_DOCK */
      if (xevent->xclient.message_type == manager->opcode_atom &&
          xevent->xclient.data.l[1]    == SYSTEM_TRAY_REQUEST_DOCK)
	{
          na_tray_manager_handle_dock_request (manager,
                                               (XClientMessageEvent *) xevent);
          return GDK_FILTER_REMOVE;
	}
      /* _NET_SYSTEM_TRAY_OPCODE: SYSTEM_TRAY_BEGIN_MESSAGE */
      else if (xevent->xclient.message_type == manager->opcode_atom &&
               xevent->xclient.data.l[1]    == SYSTEM_TRAY_BEGIN_MESSAGE)
        {
          na_tray_manager_handle_begin_message (manager,
                                                (XClientMessageEvent *) event);
          return GDK_FILTER_REMOVE;
        }
      /* _NET_SYSTEM_TRAY_OPCODE: SYSTEM_TRAY_CANCEL_MESSAGE */
      else if (xevent->xclient.message_type == manager->opcode_atom &&
               xevent->xclient.data.l[1]    == SYSTEM_TRAY_CANCEL_MESSAGE)
        {
          na_tray_manager_handle_cancel_message (manager,
                                                 (XClientMessageEvent *) event);
          return GDK_FILTER_REMOVE;
        }
      /* _NET_SYSTEM_TRAY_MESSAGE_DATA */
      else if (xevent->xclient.message_type == manager->message_data_atom)
        {
          na_tray_manager_handle_message_data (manager,
                                               (XClientMessageEvent *) event);
          return GDK_FILTER_REMOVE;
        }
    }
  else if (xevent->type == SelectionClear)
    {
      g_signal_emit (manager, manager_signals[LOST_SELECTION], 0);
      na_tray_manager_unmanage (manager);
    }

  return GDK_FILTER_CONTINUE;
}